Blogs  >  Persisting connections to Microsoft Azure Files

Persisting connections to Microsoft Azure Files

Persisting connections to Microsoft Azure Files


We recently blogged about our preview release of Azure Storage Files here. The post contained information on Azure Files, how to get started by applying for preview and explained some tools that we have to help you create the share and transfer data. This post will concentrate on how you can create a persistent connection to an Azure File share so that after a VM reboots, the share will be available for your scheduled tasks, applications, or logged in user.

Windows IaaS VMs

By default, Windows attempts to persist connections to SMB shares across reboots. However, it will not automatically persist your Azure Files credentials across reboots, so it will fail to reconnect to an Azure Files share after a reboot. There are several ways to persist these credentials, some of which are detailed below.

Persisting Credentials

CmdKey

The easiest way to establish a persistent connections is to save your storage account credentials into windows using the “CmdKey” command line utility. The following is an example command line for persisting your storage account credentials into your VM:

C:\>cmdkey /add:<yourstorageaccountname>.file.core.windows.net /user:<domainname>\<yourstorageaccountname> /pass:<YourStorageAccountKeyWhichEndsIn==>

Note: yourstorageaccountname is not your live id but the name in the endpoint. domainname here will be "AZURE"

CmdKey will also allow you to list the credentials it stored:

C:\>cmdkey /list

Currently stored credentials:

Target: Domain:target=filedemo.file.core.windows.net
Type: Domain Password
User: AZURE\filedemo

Once the credentials have been persisted, you no longer have to supply them when connecting to your share. Instead you can connect without specifying any credentials:

C:\>net use * \\filedemo.file.core.windows.net\demo1

Drive Z: is now connected to \\filedemo.file.core.windows.net\demo1.

The command completed successfully.

Then you can reboot your VM (this will disconnect you from your VM):

shutdown –t 0 –r

When your VM has restarted and you reconnect, you can open up another command window and confirm that your connection has been automatically reconnected:

C:\>net use

New connections will be remembered.

Status    Local    Remote       Network

-----------------------------------------------------------------------------

OK        Z:       \\filedemo.file.core.windows.net\demo1

                                Microsoft Windows Network

The command completed successfully.

Credential Manager

The credential manager (located under Control Panel\User Accounts) will also allow you to persist your storage account credentials.

image

User Contexts

Windows maintains different contexts for each user that is running on a VM, and sometimes it will have different contexts for the same user on the same VM at the same time. Each context can be independently connected to a different set of SMB shares, and each context will have its own drive letter mapping to the shares it is connected to.

The credentials persisted by CmdKey are available to the user who ran “CmdKey”. The connections remembered by “net use” are also available to the user who ran net use. Therefore, if you have an application that runs under a different user name, you may want to persist the credentials and connections for other user’s as well. To do that, you can use the “runas” command:

runas /user:<username> cmd.exe

That command will open a new command window. The title of the command window will read “cmd.exe (running as COMPUTERNAME\username)”. If you run “net use” in that command window, you will notice this user is not connected to any shares:

C:\>net use

New connections will be remembered.

There are no entries in the list.

You can run “CmdKey” and “net use” as above for that user, and persist both your storage credentials and connections to Azure File for that user.

Administrator Contexts

If you create a new local user on your VM, and add that user to the administrators group, then you can run commands for that user in both elevated and non-elevated contexts. Connections are not shared between elevated and non-elevated contexts, so you may want to connect separately in each context by executing “net use”. However, the persisted credentials are shared, so you only need to run “CmdKey” in one of the contexts.

Handling Scheduled Tasks

You can create scheduled tasks that run under any user on the VM, and credentials persistent with CmdKey for that user will be available to the schedule tasks. However, those scheduled tasks may run in a different user context than the logged in user, so connections to SMB shares will not be automatically re-connected in the user context that the task is running under.

For example, if you created a schedule task that runs a script that calls “net use” and writes the output to a local file, and that user had previously created a persistent connection to an Azure File share and also had persistent the credentials for that share, the output would contain:

Status      Local    Remote       Network

-----------------------------------------------------------------------------

Unavailable Z:       \\filedemo.file.core.windows.net\demo1

                                  Microsoft Windows Network

The command completed successfully.

However, the credentials are available in that context to reconnect to the share, so adding the following command to your script will re-establish the network connection:

net use z: \\filedemo.file.core.windows.net\demo1

Alternatively, the script can access files using the full UNC path rather than the mapped drive letter:

dir \\filedemo.file.core.windows.net\demo1

Also note that since the scheduled task is running in a different context that the logged in user, connections created by the schedule task may not be connected for the context of the logged in user.

Windows PaaS Roles

Persistent connections are the opposite of what you want for PaaS roles. For PaaS roles, you need to ensure that your code can connect automatically whether the system has started a fresh instance, or if your instance has just been restart.

PInvoke WNetAddConnection2

You can map a drive letter in your PaaS role startup code by pinvoking WNetAddConnection2. The following code declares a set of structures you need to establish a mapping from an Azure Files share to a local drive letter.

[DllImport("Mpr.dll",
            EntryPoint = "WNetAddConnection2",
            CallingConvention = CallingConvention.Winapi)]
private static extern int WNetAddConnection2(NETRESOURCE lpNetResource,
                                             string lpPassword,
                                             string lpUsername,
                                             System.UInt32 dwFlags);


[DllImport("Mpr.dll",
           EntryPoint = "WNetCancelConnection2",
           CallingConvention = CallingConvention.Winapi)]
private static extern int WNetCancelConnection2(string lpName,
                                                System.UInt32 dwFlags,
                                                System.Boolean fForce);


[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
    public int dwScope;
    public ResourceType dwType;
    public int dwDisplayType;
    public int dwUsage;
    public string lpLocalName;
    public string lpRemoteName;
    public string lpComment;
    public string lpProvider;
};


public enum ResourceType
{
    RESOURCETYPE_DISK = 1,
};

Then you can write a method that will mount the share on a given drive letter:

public static void MountShare(string shareName,
                              string driveLetterAndColon,
                              string username,
                              string password)
{
    if (!String.IsNullOrEmpty(driveLetterAndColon))
    {
        // Make sure we aren't using this driveLetter for another mapping
        WNetCancelConnection2(driveLetterAndColon, 0, true);
    }


    NETRESOURCE nr = new NETRESOURCE();
    nr.dwType = ResourceType.RESOURCETYPE_DISK;
    nr.lpRemoteName = shareName;
    nr.lpLocalName = driveLetterAndColon;


    int result = WNetAddConnection2(nr, password, username, 0);


    if (result != 0)
    {
        throw new Exception("WNetAddConnection2 failed with error " + result);
    }
}

Then you can call this method from the “OnStart()” method of your role:

MountShare("\\\\filedemo.file.core.windows.net\\demo1",
           "z:",
           "filedemo",
           "<YourStorageAccountKeyWhichEndsIn==>");

From that point forward in your worker role, you will be able to read and write files to the Azure File share using either the drive letter, or the full UNC path:

File.Create("z:\\WNetAddConnection2.txt");
File.Create(\\\\filedemo.file.core.windows.net\\demo1\\UNC.txt);

Web Roles and User Contexts

The OnStart() method of an Azure Web Role runs in a different user context than is used to render pages of the web site. Therefore, if you want to reference your Azure Files shares from the code that renders the pages, you should put the code from above in your Global.Application_Start() method rather than WebRole.OneStart().

Linux VM

Linux has a variety of methods for automatically mounting shares during startup, but we only experimented with one method, and only on Ubuntu 14.04 LTS.

Persist Connections with Fstab

Linux has a file called “fstab” in /etc that can be used to mount drives and shares during startup. One way to automatically mount an Azure Files share during boot is to add a line to /etc/fstab. The following text should be placed on a single line in the file:

//<yourstorageaccountname>.file.core.windows.net/demo1 /home/azureuser/smb cifs vers=2.1,dir_mode=0777,file_mode=0777,username=AZURE\<yourstorageaccountname>,password=<YourStorageAccountKeyWhichEndsIn==>

There are several parts of this line, described below in this table:

Part Example Description
Share URL //filedemo.file.core.windows.net/demo1 The URL of an Azure Files share that you previously created
Mount point /home/azureuser/smb The path to an empty directory on your Linux VM that you previously created where you want the share to be mounted.
File system Cifs The type of file system you want to mount. For Azure Files, this will be ‘cifs’.
Mount Parameters vers=2.1 The version of SMB to use, in this case version 2.1
dir_mode=0777 The permissions mask used for directories in the Azure Files share, in this case full permissions.
file_mode=0777 The permissions mask used for files in the Azure Files share, in this case full permissions.
username=filedemo For Azure Files, this username needs to be you storage account name.
password=StorageAccountKey== For Azure Files, this password needs to be your full storage account key.

There are many other options that can be included in your fstab file. For more information see the relevant document for the Linux distribution you are using.

Summary

Our previous post introduced Azure Files and this post concentrates on steps to help you create persistent connections to Azure File shares so that connections to shares are available after a reboot. As always we would love to hear feedback via comments on this blog, Azure Storage MSDN forum, or send email to mastoragequestions@microsoft.com.

Andrew Edwards

Please see these links for more information:

Azure Files 2014-04-14 version

Introducing Microsoft Azure File Service

AzCopy

Azure File PowerShell Cmdlets (CTP)

Storage .NET Client Library 4.0 for 2014-04-14 version


Comments (19)

  1. Dave says:

    Any suggestions on how to do this in a PHP web role in a cloud service. There is no equivalent to Application_Start in php and it's expensive to check for drive letter and map it all the time?

  2. MPalos says:

    Keep getting WNetAddConnection2 error 86 for PaaS. We don't have domains and network users, only could of cloud service instances and would like to have shared file system in between. So, everything that documentation refers afterwards is having some network enabled accounts on PaaS instances ?

    Could you please post complete example of persistent connection to file service location? Something of combined example from introduction but that doesn't rely on usage of net use (since it isn't persistent).

    Thanks

  3. serdar.ozler@outlook.com says:

    @Dave, as you also mentioned, there is no equivalent of Application_Start in PHP. Therefore, we recommend checking for existence of a file in your Azure Files share and mapping the share to a drive letter if the file cannot be found. It will mount the share only the first time a request comes in and then simply check a file’s existence in all other requests. For example;

    <?php

    if (!file_exists("z:\test.php"))

    {

      system("net use z: \\account.file.core.windows.net\share /u:account key 2>nul 1>nul");

    }

    ?>

  4. Corgalore says:

    Do you think Azure Files would be a viable solution for storing ASP.Net website files that use multiple Azure VMs as IIS front-ends? Will the servers be able to reliably re-connect to the Share in order to serve the content?

  5. Regular Guy says:

    Hi Corgalore, I use Azure Files to create files on Linux virtual machines and make them available via Windows IIS and it works very well. So from my experience, the answer to your question is yes.

  6. spike says:

    I am calling MountShare() from my Global.Application_Start() in my Azure website as you suggest and I am getting "WNetAddConnection2 failed with error 5" – which I believe is a permissions thing. Is it that the account doesn't have local admin privileges? How might I go about resolving this?

  7. Andrew Edwards says:

    Hi Spike,

    Mounting an Azure File Share from an Azure Website is not currently supported.  Azure File Shares can only be connected to Azure Virtual Machines.

    Thanks

    Andrew Edwards

    Microsoft Azure Storage

  8. 2nd try says:

    Is there a cleaner/no-code solution for ASP.NET apps than referencing a Windows API call? I want to be able to deploy an ASP.NET app to two Azure VMs with only a configuration file change (pointing to \uncpath… in production, c:localfolder on developer PCs). I started with a fresh Windows 2012 VM, a new Azure file service, and a one page ASP.NET app that does File.ReadAllText() from the UNC path of the azure file service. Cmdkey saved credentials successfully and I could access the share interactively, either as my app pool account with runas or the local admin account. However, ASP.NET can never connect to the UNC path ("user name or password is incorrect"). I've tried running the app pool as local Administrator, granting rights under local policies, using mklink to create a symbolic link – nothing works and it's frustrating. What I did get to work was WNetAddConnection2 in the global.asax, but this seems like a dirty hack. I'm using all Microsoft technology, would like to see a solution in IIS or even native code. The Azure file service only gets me about 90% of where I need to be. Can we specify credentials on the file share or have a setting for no authentication from designated VM IPs?

  9. Andrew Edwards says:

    Hi "2nd try",

    ASP.NET web pages run under the "Network Service" context, so you need to run "cmdkey" or "net use" under that context.  As mentioned above, one way to do that is by running from global.asax.  Another way is to use psexec (technet.microsoft.com/…/bb897553.aspx) and run "net use" from a startup script:

       psexec.exe -accepteula -u "NT AUTHORITYNETWORK SERVICE" net use z: \act.file.core.windows.nettest /u:act key==

       echo "done"

    (Note the call to echo after psexec.  For your role to start successfully, the last command in the script must return '0')

    You also need to add the startup script to your ServiceDefinition.csdef:

       <Startup>

         <Task commandLine="Startup.cmd" executionContext="elevated" taskType="simple"/>

       </Startup>

    And add both "psexec.exe" and "startup.cmd" to your webrole's bin directory.

    Thanks

    Andrew Edwards

    Microsoft Azure Storage

  10. 2nd try says:

    I ended up creating an account with the user name of the Azure file account and key as the password. What led me down that path was the need for a virtual directory pointing to some static files on the shared drive. Creating a local account on the VM with same name as the Azure file account allowed me to do a "Connect As.." when setting up the virtual directory in IIS. As it turns out setting that account as the app pool identity seems to allow access for the ASP.NET app as well. Thanks again for the feedback. Through scouring blogs like this one I've been able to set up a 2VM scenario with SQL Azure as the back end and shared session/file access.

  11. access shared azure files mapping with php running on IIS VM says:

    I spend a lot of time trying to make my shared folder accessible to PHP running on my VM with IIS.

    I finally figured it out and think it might be usefull to share my solution.

    1) create a windows user   and affect it to IUSR group. lets call it azureIISUser

    2) open  powershell console and execute the following script: like explained above in "user context"

         a)  runas /user:<SERVERNAME>azureIISUser cmd.exe ( replace <SERVERNAME> with the name of your server)

            That command will open a new DOS console running under the azureIISUser user.

          b)in the DOS console, execute the following script:( if you have not already registered the shared credential)

             cmdkey /add:<yourstorageaccountname>.file.core.windows.net /user:<yourstorageaccountname> /pass:<YourStorageAccountKeyWhichEndsIn==>

         c) Then map a drive to the shared folder for the new user (here 'azureIISUser')

    In the DOS console : net use z: \<yourstorageaccountname>.file.core.windows.net<sharedfolder>

    3)  Set Up IIS to use the new user:

       open IIS, select the site that need access to the mapped shared

       a) edit Authentification settings: Authentification settings -> anonymous authentification ->edit->select aplication pool identity

       b) You can now affect the new user to the application pool used by the site. If you affect the user to the application pool without changing the setting of anonymous acces, the site will keep running under IUSER and will not have access to the shared folder.

  12. Nazik Huq says:

    What are the performance implications of having all shares under one storage account versus creating one share/storage account in pairs?

  13. jaidevh1@hotmail.com says:

    @Naziq, It is better to have multiple shares under single storage account and there is no perf implications. However, please ensure that your ingress/egress and request/sec is within the limits of a single storage account (see msdn.microsoft.com/…/dn249410.aspx) and use multiple storage accounts if you need to scale beyond the limits.

  14. Vladimir says:

    Is it possible to create syspreped image which will have file share automatically mounted when new VMs are created from it?

  15. Andrew Edwards says:

    Hi Vladimir,

    Connections to Azure Files are per user, not per VM.  So you can't create a sysprep'd image with a shre automatically mounted.  Instead, you should have your service/application mount the share from the user context in which it runs or will run.

    Thanks

    Andrew Edwards

    Microsoft Azure Storage

  16. Vladimir says:

    @Andrew Edwards thanks for your answer.

    It would be nice if I could sysprep the image with the script which would mount the file share automatically. So when I create a VM out of that image, file share is automatically available. I could put a net use line in a script.

    But I'm not sure if setting up a script which would execute at Windows Startup (like a Windows service?) is possible? If we talk about syspreped image.

  17. developerBillCooper says:

    Storage Team – I need some help.  I have been using azure files preview for several months and it really fits our use case well.  But I am experiencing a major roadblock that is preventing us from fully adopting a solution that would include azure files.

    We are mounting Azure File shares from Azure Ubuntu 14.04 LTS VMs and all is fine – for a while.  We have found that the share connection fails after some unknown amount of time.  A reboot always fixes the problem.  I have tried to troubleshoot this on my own, but have not been able to pinpoint the exact issue.  I'm not sure if the problem is Ubuntu, cifs, networking, …

    This issue is very consistent.  A have previsioned several Azure Ubuntu 14.04 LTS VMs each mounted to a different share on the same storage account, and they all eventually fail in this way.

    Azure files is a great feature, and is exactly what we are looking for, but this issue has me very concerned about going forward on a large scale.  Please help.

    This is what I am seeing in /var/log/kern.log:

    Mar  4 23:50:42 <MY-VM> kernel: [1751285.617707] CIFS VFS: Server <MY-STORAGE-ACCOUNT>.file.core.windows.net has not responded in 120 seconds. Reconnecting…

    Mar  5 02:07:56 <MY-VM> kernel: [1759519.155512] CIFS VFS: Server <MY-STORAGE-ACCOUNT>.file.core.windows.net has not responded in 120 seconds. Reconnecting…

    Mar  5 05:28:07 <MY-VM> kernel: [1771530.473580] CIFS VFS: Server <MY-STORAGE-ACCOUNT>.file.core.windows.net has not responded in 120 seconds. Reconnecting…

    Running the command cat /proc/fs/cifs/DebugData gives the following result:

    CIFS Version 2.02

    Features: dfs fscache lanman posix spnego xattr acl

    Active VFS Requests: 0

    Servers:

    1) entry for <MY-STORAGE-ACCOUNT-IP> not fully displayed

           TCP status: 4

           Local Users To Server: 1 SecMode: 0x3 Req On Wire: 0

           Shares:

           1) \<MY-STORAGE-ACCOUNT>.file.core.windows.netssd Mounts: 1 DevInfo: 0x20 Attributes: 0x6

           PathComponentMax: 255 Status: 0x1 type: DISK    DISCONNECTED

           MIDs:

    2) entry for <MY-STORAGE-ACCOUNT-IP> not fully displayed

           TCP status: 4

           Local Users To Server: 1 SecMode: 0x3 Req On Wire: 0

           Shares:

           1) \<MY-STORAGE-ACCOUNT>.file.core.windows.netssd Mounts: 1 DevInfo: 0x20 Attributes: 0x6

           PathComponentMax: 255 Status: 0x1 type: DISK    DISCONNECTED

           MIDs:

    3) entry for <MY-STORAGE-ACCOUNT-IP> not fully displayed

           TCP status: 4

           Local Users To Server: 1 SecMode: 0x3 Req On Wire: 0

           Shares:

           1) \<MY-STORAGE-ACCOUNT>.file.core.windows.netssd Mounts: 1 DevInfo: 0x20 Attributes: 0x6

           PathComponentMax: 255 Status: 0x1 type: DISK    DISCONNECTED

           MIDs:

    4) entry for <MY-STORAGE-ACCOUNT-IP> not fully displayed

           TCP status: 4

           Local Users To Server: 1 SecMode: 0x3 Req On Wire: 0

           Shares:

           1) \<MY-STORAGE-ACCOUNT>.file.core.windows.netssd Mounts: 1 DevInfo: 0x20 Attributes: 0x6

           PathComponentMax: 255 Status: 0x1 type: DISK    DISCONNECTED

           MIDs:

    ….

  18. Atul - MSFT says:

    developerBillCooper, we will need to look into the account in more detail to see what is going on. Can you send some details in a separate email to ascl @ microsoft.com? We will need the following details:

    1. Storage account name (do NOT send the storage account key)

    2. Time when you saw the connection drop (I cant tell the timezone from your logs below)

    Thanks,

    Atul

  19. JMarcus says:

    Are there plans to allow access to Azure File shares from Azure WebApps any time soon?