Stop-AzureRmVM give us a simple way to start and stop VMs in Azure. The only thing is, they work synchronously, so we have to wait for the whole startup or deallocation process to finish before the command returns. If you have to start up anything more than a few virtual machines then using these commands is going to take a long time. If you are working at serious scale in the cloud and are starting up tens or even hundreds of VMs at a time then using these commands is not going to be a option. It would simply take too long to start or stop them one by one. What we need is a way to run these commands asynchronously and startup/shutdown many VMs in parallel.
I want to demonstrate a few ways we can use multi threading in Powershell to achieve this.
I previously posted a Powershell Multi Threaded Cookbook. Lets try and apply some of those methods to this problem.
Powershell background jobs provide a generic mechanism to run scripts on a background thread. Here is my implementation of starting and stopping ARM VMs using background jobs.
The first thing to note is the parameter
$ProfilePath. When a background job is run the background process will not be authenticated for Azure even if the main thread is. In other words, each background job has to authenticate into Azure itself. One way we can achieve this is by persisting our AzureRM profile to disk and then let the background job read it in. It seems a bit of a hack and it is. I believe there are plans to improve this scenario in Azure Powershell. Please see this thread for more details. See the section on Workflows for an alternative approach.
Once we have sorted out the authentication things go quite easily. Simply instantiate a background job for each VM you want to start or stop and pass in the correct arguments.
Finally we poll the jobs and wait for them to come out of the Running state. The usual rules around using
Receive-Job to manage Powershell background jobs will of course apply.
Note: this example spins up one background process for every VM you are starting/stopping.
Here is an example of how to call this command
Workflows can give us another approach. Its Powershell but driven by Windows Workflow. Workflows provide out of the box support for parallel processing. Once again we need to authenticate to Azure in each background thread but this time we will pass a
PSCredential into the script and use
Add-AzureRmAccount to authenticate using this credential. The credential has to be a service principal or Azure Active Directory account.
Add-AzureRmAccount does not work with LiveIds. Note the
foreach -parallel call, that’s the out of the box support workflows give us for parallel processing.
Note: When using workflows and the -parallel switch we have no control on how many background processes Powershell spins up. That is handled for us behind the scenes.
Our third and final example uses runspaces to handle all the background threading. This method gives us the most control over the multithreading. I wrote about it in more detail in my Multithreading Cookbook.
Note how we can specify the number of background threads we want to use.
So that’s three very different ways to tackle the same problem. If you are working with classic VMs all the above scripts can be modified to use the classic cmdlets.