Search code examples
powershellazureazure-powershelldsc

Drive Mapping with Azure Scale Sets using Desired State Configuration


I am running into an interesting issue. Maybe you fine folks can help me understand what's happening here. If there's a better method, I'm all ears.

I am running a DSC Configuration on Azure and would like to map a drive. I've read this really isn't what DSC is for, but I am not aware of any other way of doing this outside of DSC with Azure Scalesets. Here's the portion of the script I am running into issues:

Script MappedDrive
    {
        SetScript = 
        {
        $pass = "passwordhere" | ConvertTo-SecureString -AsPlainText -force
        $user = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "username",$pass
        New-PSDrive -Name W -PSProvider FileSystem -root \\azurestorage.file.core.windows.net\storage -Credential $user -Persist
        }
        TestScript = 
        {
            Test-Path -path "W:"
        }
        GetScript = 
        {
        $hashresults = @{}
        $hashresults['Exists'] = test-path W:
        }
    }

I've also attempted this code in the SetScript section:

(New-Object -ComObject WScript.Network).MapNetworkDrive('W:','\\azurestorage.file.core.windows.net\storage',$true,'username','passwordhere')

I've also tried a simple net use command to map the drive instead of the fancy, New-Object or New-PSDrive cmdlets. Same behavior.

If I run these commands (New-Object/Net Use/New-PSDrive) manually, the machine will map the drive if I run it with a separate drive letter. Somehow, the drive is attempting to be mapped but isn't mapping.

Troubleshooting I've done:

  • There is no domain in my environment. I am simply attempting to create a scale set and run DSC to configure the machine using the storage account credentials granted upon creation of the storage account.
  • I am using the username and password that is given to me by the Storage Account user id and access key (randomly generated key, with usually the name of the storage account as the user).
  • Azure throws no errors on running the DSC module (No errors in Event Log, Information Only - Resource execution sequence properly lists all of my sequences in the DSC file.)
  • When I log into the machine and check to see if the drive is mapped, I run into a disconnected network drive on the drive letter I want (W:).
  • If I open Powershell, I receive an error: "Attempting to perform the InitializeDefaultDrives operation on the 'FileSystem' provider failed."
  • If I run "Get-PSDrive" the W: drive does not appear.
  • If I run the SetScript code manually inside a Powershell Console, the mapped drive works fine under a different drive letter.
  • If I try to disconnect the W: drive, I receive "This network connection does not exist."
  • I thought maybe DSC needed some time before mapping and added a Sleep Timer, but that didn't work. Same behavior.

Solution

  • I had a similar problem before, while it didn't involve DSC, mounting an Azure File share would be fine until the server would be restarted, then it would appear as a disconnected drive. This happend if i used New-Object/Net Use/New-PSDrive with the persist option.

    The answer to that issue, i found in the updated docs

    Persist your storage account credentials for the virtual machine

    Before mounting to the file share, first persist your storage account credentials on the virtual machine. This step allows Windows to automatically reconnect to the file share when the virtual machine reboots. To persist your account credentials, run the cmdkey command from the PowerShell window on the virtual machine. Replace with the name of your storage account, and with your storage account key.

    cmdkey /add:<storage-account-name>.file.core.windows.net /user:<storage-account-name> /pass:<storage-account-key>

    Windows will now reconnect to your file share when the virtual machine reboots. You can verify that the share has been reconnected by running the net use command from a PowerShell window.

    Note that credentials are persisted only in the context in which cmdkey runs. If you are developing an application that runs as a service, you will need to persist your credentials in that context as well.

    Mount the file share using the persisted credentials

    Once you have a remote connection to the virtual machine, you can run the net use command to mount the file share, using the following syntax. Replace with the name of your storage account, and with the name of your File storage share.

    net use <drive-letter>: \\<storage-account-name>.file.core.windows.net\<share-name> example : net use z: \\samples.file.core.windows.net\logs

    Since you persisted your storage account credentials in the previous step, you do not need to provide them with the net use command. If you have not already persisted your credentials, then include them as a parameter passed to the net use command, as shown in the following example.

    Edit: I don't have an Azure VM free to test it on, but this works fine on a Server 2016 hyper-v vm

    Script MapAzureShare
        {
            GetScript = 
            {
    
            }
            TestScript = 
            {
                Test-Path W:
            }
            SetScript = 
            {
                Invoke-Expression -Command "cmdkey /add:somestorage.file.core.windows.net /user:somestorage /pass:somekey"
                Invoke-Expression -Command "net use W: \\somestorage.file.core.windows.net\someshare"
            }
            PsDscRunAsCredential = $credential
        }
    

    In my brief testing the drive would only appear after the server was rebooted.