Start and Stop Azure VM’s (and more) in Parallel from Powershell

Edit 2017: With the change to AzureRM this approach need some tweaking, see this new GIST for how to allow AzureRM to execute commands in Powershell jobs. The script itself is used to remove deployment history for a resource group but can easily be edited to work on VMs.

So I’ve got a demo that I’ve put together that uses a LOAD of Azure VM’s to demonstrate scripting against them.

To make sure I don’t get charged for them while I’m not using them I’ve got the following powershell to start and stop them:

Get-AzureVM | Stop-AzureVM –Force

Get-AzureVM | Start-AzureVM

I notice that this took a longer than I was expecting and so I started to do some digging. It turn out the PowerShell pipeline is executing these API requests in a synchronous way. Firing off the first request, waiting for the response and then, when completed, moving on to the next. This wouldn’t be a problem if I didn’t have loads of VM’s!

So I wrote the following, it uses PowerShell Jobs (think Task<T> if you’re a C# person), to kick these off as background jobs that run in parallel. (nb. You have to pass the variables in as arguments to the script block)

$vms = Get-azurevm | ?{ $_.Status -eq "StoppedDeallocated"}
$jobs = @()
foreach ($vm in $vms)
{
$params = @($vm.Name, $vm.ServiceName)
$job = Start-Job -ScriptBlock {
param($ComputerName, $ServiceName)
start-Azurevm -Name $ComputerName -ServiceName $ServiceName
} -ArgumentList $params
$jobs = $jobs + $job
}
# Wait for it all to complete
Wait-Job -Job $jobs
# Getting the information back from the jobs
Get-Job | Receive-Job
view raw gistfile1.ps1 hosted with ❤ by GitHub

 

Now we get this lovely output. These all run as individual jobs and complete asynchronously, we then wait for all of them (think WaitAll() for C#). Now I can start all of my machines in the demo really quickly!

This is really useful in other scenarios too, think of any time you’re waiting on azure management API and the actions could be done simultaneously.

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command

—     —-            ————-   —–         ———–     ——–             ——-

22     Job22           BackgroundJob   Running       True            localhost            …

24     Job24           BackgroundJob   Running       True            localhost            …

26     Job26           BackgroundJob   Running       True            localhost            …

28     Job28           BackgroundJob   Running       True            localhost            …

30     Job30           BackgroundJob   Running       True            localhost            …

RunspaceId           : 88465362-c8ce-45de-866d-9ced85cc3e40

OperationDescription : Start-AzureVM

OperationId          : 60712d20-311b-6cd5-b0df-9a750f024d0c

OperationStatus      : Succeeded

RunspaceId           : 3a9e93cf-7d16-4a2c-aeb7-4493e8ec8abb

OperationDescription : Start-AzureVM

OperationId          : fb494c0c-3728-62d4-b288-b8d391ad32d7

OperationStatus      : Succeeded

RunspaceId           : c1144e74-ba7c-4aa3-bcbb-aa9f2bd72fdf

OperationDescription : Start-AzureVM

OperationId          : 194254da-be36-6c7d-a147-67a980816c8e

OperationStatus      : Succeeded

RunspaceId           : 44af74a2-fc11-4e9b-8158-d9d84dd49d9e

OperationDescription : Start-AzureVM

OperationId          : 86059d5d-22ee-6a55-871d-28bcf52241a2

OperationStatus      : Succeeded

RunspaceId           : a44b51e9-11cc-4d31-875e-5e0fd16b935a

OperationDescription : Start-AzureVM

OperationId          : d4e2fcce-b270-6d6e-ad0c-8322e2c4df23

OperationStatus      : Succeeded

By:

Posted in:


5 responses to “Start and Stop Azure VM’s (and more) in Parallel from Powershell”

  1. Just a tip: concurrent stop/start vm in the same cloud service does not work, because that operation requires an exclusive access to the cloud service resources, and you will end up with just one job running, and the others in Completed state, returning the error “An exception occurred when calling the ServiceManagement API. HTTP Status Code: 409. Service Management Error Code: ConflictError. Message: Windows Azure is currently
    performing an operation with x-ms-requestid xxxxxxxxx on this deployment that requires exclusive access…”

    In this case I just run a command like this:

    Start-Job -ScriptBlock { Get-AzureVM | ?{ $_.Status -eq “StoppedDeallocated” } | Start-AzureVM }

    and to stop:

    Start-Job -ScriptBlock { Get-AzureVM | ?{ $_.Status -eq “StoppedDeallocated” } | Stop-AzureVM -Force }

    this will run in background, but will do a sequential bootstrap, avoiding the conflict error, and of course is much slower than the other approach, but it could be changed to run this per cloud service, so at least per cloud service could be fired out a new job, and parallelize per cloud service.

Leave a comment

Blog at WordPress.com.