Windows Azure Powershell Copying file to VM Windows Azure Powershell Copying file to VM powershell powershell

Windows Azure Powershell Copying file to VM


Here is ano ther approach that I documented here. It involves

  1. Creating and mounting an empty local VHD.
  2. Copying your files to the new VHD and dismount it.
  3. Copy the VHD to azure blob storage
  4. Attach that VHD to your VM.

Here is an example:

#Create and mount a new local VHD$volume = new-vhd -Path test.vhd -SizeBytes 50MB | `  Mount-VHD -PassThru | `  Initialize-Disk -PartitionStyle mbr -Confirm:$false -PassThru | `  New-Partition -UseMaximumSize -AssignDriveLetter -MbrType IFS | `  Format-Volume -NewFileSystemLabel "VHD" -Confirm:$false#Copy my files  Copy-Item C:\dev\boxstarter "$($volume.DriveLetter):\" -RecurseDismount-VHD test.vhd#upload the Vhd to azureAdd-AzureVhd -Destination http://mystorageacct.blob.core.windows.net/vhdstore/test.vhd `  -LocalFilePath test.vhd#mount the VHD to my VMGet-AzureVM MyCloudService MyVMName | `  Add-AzureDataDisk -ImportFrom `  -MediaLocation "http://mystorageacct.blob.core.windows.net/vhdstore/test.vhd" `  -DiskLabel "boxstarter" -LUN 0 | `  Update-AzureVM


Here is some code that I got from some powershell examples and modified. It works over a session created with New-PSSession. There's a cool wrapper for that also included below. Lastly, I needed to send a whole folder over so that's here too..

Some example usage for tying them together

# open remote session$session = Get-Session -uri $uri -credentials $credential # copy installer to VMWrite-Verbose "Checking if file $installerDest needs to be uploaded"Send-File -Source $installerSrc -Destination $installerDest -Session $session -onlyCopyNew $true<#.SYNOPSIS  Returns a session given the URL .DESCRIPTION  http://michaelcollier.wordpress.com/2013/06/23/using-remote-powershell-with-windows-azure-vms/#>function Get-Session($uri, $credentials){    for($retry = 0; $retry -le 5; $retry++)    {      try      {        $session = New-PSSession -ComputerName $uri[0].DnsSafeHost -Credential $credentials -Port $uri[0].Port -UseSSL        if ($session -ne $null)        {            return $session        }        Write-Output "Unable to create a PowerShell session . . . sleeping and trying again in 30 seconds."        Start-Sleep -Seconds 30      }      catch      {        Write-Output "Unable to create a PowerShell session . . . sleeping and trying again in 30 seconds."        Start-Sleep -Seconds 30      }    }}<#.SYNOPSIS  Sends a file to a remote session.  NOTE: will delete the destination before uploading.EXAMPLE  $remoteSession = New-PSSession -ConnectionUri $remoteWinRmUri.AbsoluteUri -Credential $credential  Send-File -Source "c:\temp\myappdata.xml" -Destination "c:\temp\myappdata.xml" $remoteSession  Copy the required files to the remote server     $remoteSession = New-PSSession -ConnectionUri $frontEndwinRmUri.AbsoluteUri -Credential $credential    $sourcePath = "$PSScriptRoot\$remoteScriptFileName"    $remoteScriptFilePath = "$remoteScriptsDirectory\$remoteScriptFileName"    Send-File $sourcePath $remoteScriptFilePath $remoteSession    $answerFileName = Split-Path -Leaf $WebPIApplicationAnswerFile    $answerFilePath = "$remoteScriptsDirectory\$answerFileName"    Send-File $WebPIApplicationAnswerFile $answerFilePath $remoteSession    Remove-PSSession -InstanceId $remoteSession.InstanceId#>function Send-File{    param (        ## The path on the local computer        [Parameter(Mandatory = $true)]        [string]        $Source,        ## The target path on the remote computer        [Parameter(Mandatory = $true)]        [string]        $Destination,        ## The session that represents the remote computer        [Parameter(Mandatory = $true)]        [System.Management.Automation.Runspaces.PSSession]         $Session,        ## should we quit if file already exists?        [bool]        $onlyCopyNew = $false        )    $remoteScript =    {        param ($destination, $bytes)        # Convert the destination path to a full filesystem path (to supportrelative paths)        $Destination = $ExecutionContext.SessionState.`        Path.GetUnresolvedProviderPathFromPSPath($Destination)        # Write the content to the new file        $file = [IO.File]::Open($Destination, "OpenOrCreate")        $null = $file.Seek(0, "End")        $null = $file.Write($bytes, 0, $bytes.Length)        $file.Close()    }    # Get the source file, and then start reading its content    $sourceFile = Get-Item $Source    # Delete the previously-existing file if it exists    $abort = Invoke-Command -Session $Session {        param ([String] $dest, [bool]$onlyCopyNew)        if (Test-Path $dest)         {             if ($onlyCopyNew -eq $true)            {                return $true            }            Remove-Item $dest        }        $destinationDirectory = Split-Path -Path $dest -Parent         if (!(Test-Path $destinationDirectory))        {            New-Item -ItemType Directory -Force -Path $destinationDirectory         }        return $false    } -ArgumentList $Destination, $onlyCopyNew    if ($abort -eq $true)    {        Write-Host 'Ignored file transfer - already exists'        return    }    # Now break it into chunks to stream    Write-Progress -Activity "Sending $Source" -Status "Preparing file"    $streamSize = 1MB    $position = 0    $rawBytes = New-Object byte[] $streamSize    $file = [IO.File]::OpenRead($sourceFile.FullName)    while (($read = $file.Read($rawBytes, 0, $streamSize)) -gt 0)    {        Write-Progress -Activity "Writing $Destination" -Status "Sending file" `            -PercentComplete ($position / $sourceFile.Length * 100)        # Ensure that our array is the same size as what we read from disk        if ($read -ne $rawBytes.Length)        {            [Array]::Resize( [ref] $rawBytes, $read)        }        # And send that array to the remote system        Invoke-Command -Session $session $remoteScript -ArgumentList $destination, $rawBytes        # Ensure that our array is the same size as what we read from disk        if ($rawBytes.Length -ne $streamSize)        {            [Array]::Resize( [ref] $rawBytes, $streamSize)        }        [GC]::Collect()        $position += $read    }    $file.Close()    # Show the result    Invoke-Command -Session $session { Get-Item $args[0] } -ArgumentList $Destination}<#.SYNOPSIS  Sends all files in a folder to a remote session.  NOTE: will delete any destination files before uploading.EXAMPLE  $remoteSession = New-PSSession -ConnectionUri $remoteWinRmUri.AbsoluteUri -Credential $credential  Send-Folder -Source 'c:\temp\' -Destination 'c:\temp\' $remoteSession#>function Send-Folder {    param (        ## The path on the local computer        [Parameter(Mandatory = $true)]        [string]        $Source,        ## The target path on the remote computer        [Parameter(Mandatory = $true)]        [string]        $Destination,        ## The session that represents the remote computer     #   [Parameter(Mandatory = $true)]        [System.Management.Automation.Runspaces.PSSession]         $Session,        ## should we quit if files already exist?        [bool]        $onlyCopyNew = $false    )    foreach ($item in Get-ChildItem $Source)    {        if (Test-Path $item.FullName -PathType Container) {            Send-Folder $item.FullName "$Destination\$item" $Session $onlyCopyNew        } else {            Send-File -Source $item.FullName -Destination "$destination\$item" -Session $Session -onlyCopyNew $onlyCopyNew        }    }}


You cannot use PowerShell to copy a file directly to a Virtual Machine's OS disk (or even to one of its attached disks). There's no API for communicating directly with a Virtual Machine's innards (you'd need to create your own custom service for that.

You can use PowerShell to upload a file to a Blob, with Set-AzureStorageBlobContent.At that point, you could notify your running app (possibly with a Queue message?) on your Virtual Machine that there's a file waiting for it to process. And the processing could be as simple as copying the file down to the VM's local disk.