Using Remote PowerShell with Windows Azure VMs

I’ve been doing a little more work with Windows Azure Virtual Machines and PowerShell lately. With the PowerShell cmdlets I can create VMs and Virtual Networks in a quick and repeatable fashion.  After the machines are created, I still need to configure the machines.  This is where Remote PowerShell can help.

Remote PowerShell

With Remote PowerShell, it’s possible to create a remote connection to the VM, and execute PowerShell cmdlets against that VM.  This allows us to remotely configure that VM – carrying out tasks like configuring Window Server roles and modifying other various settings.  See Michael Washam’s blog post for a great primer on Remote PowerShell with Windows Azure VMs.

One of the quirks I’ve noticed lately when working with Remote PowerShell sessions and Windows Azure VMs is that the Remote PowerShell session takes a little while to be “ready” even after the VM is started.  Let’s take the following scenario:

  1. Create a new VM
  2. Using Remote PowerShell, install & configure a new Windows Server role.  Part of the rule’s install process is to reboot the machine.
  3. After the machine reboots, connect again via Remote PowerShell to do some more work.

I’ve had several occasions where trying to connect to the VM after a reboot fails.  I assumed checking for the instance’s status to be “ReadyRole” would be sufficient.  Nope.

# Wait for server to reboot
$VMStatus = Get-AzureVM -ServiceName $serviceName -name $vmName

While ($VMStatus.InstanceStatus -ne "ReadyRole")
{
  write-host "Waiting...Current Status = " $VMStatus.Status
  Start-Sleep -Seconds 15

  $VMStatus = Get-AzureVM -ServiceName $serviceName -name $vmName
}

It’s the cloud – retry

Like most things in the cloud, in order to be successful you have to plan for failure and retry.  So even though the role might report that it is “ReadyRole”, that’s not enough for a Remote PowerShell session to connect reliably.

The steps I’ve taken to try to remedy this situation:

  1. Get the URI for Remote PowerShell on the  Windows Azure VM
  2. In a simple loop, continue to try to connect to the Remote PowerShell session.  If unsuccessful, wait for a few seconds and try again.
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)
    {
      break
    }

    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
  }
}

So far this approach seems to be working fairly well.  I’ve actually dropped this logic into a little function that returns the session.  That makes it a little easier to reuse across several different scripts.