Tuesday, July 11, 2017

Start Stop Multiple Azure VMs on schedule using Azure Automation


I searched through many, many, many…articles written about Azure VM stop(de-allocate) to save cost. Every article only targets single Azure VM to shutdown (de-allocate). None of the articles target start and Shutdown of multiple Azure VMs using automation. I am going to address this using Azure powershell in this article.

What all Cool features of azure VM start/ stop my script offers?

If you have multiple Azure VMs present in your azure subscription; and you want to start or stop few of them on schedule then you can use below azure PowerShell scripts. It will have below features –
è  Add/ remove the VM names from the list of start/ stop schedule easily. [You don’t need to have PowerShell knowledge]
è  Use same script in multiple different Azure runbooks, with different Azure VM names to start and stop; that too with different schedules.
è  In case any wrong/ nonexistent VM name added to the list, script takes care of giving relative user-friendly message and do not throw error. It continues with other remaining set of Azure VMs and perform start or stop.
è  Can be used with single VM as well if required.
è  You start and stop azure VMs based on schedule hence obviously you optimize or save Azure cost.
è  Script is available for download; hence you can own it to change in future. [that’s cool 😊]
I can say all above feature are nothing but the “Key differentiator” or “Value Proposition” from other Azure VM shut down/ start automation blogs/ scripts. [These marketing terms; I hear them a lot 😊]

Fundamentals of Azure VM cost optimization

Azure VM are made of Compute and Storage. Compute is nothing but Core (number of cores/ CPUs) and RAM you get when you provision Azure VM. Storage is nothing but the C drive or other letter drives; except D drive for windows and Sdb drive for Linux]. These drives are nothing but disks or .vhd files present in Azure storage account [if VM is unmanaged] else disks or .vhd files will be part of your subscription [if VM is created using managed disks].
When we say you stop Azure VM from portal or using PowerShell command “Stop-AzureRMVm” basically Compute part of VM is released (or de-allocated). It is worth to mention here that “STORAGE PART REMAINS”.
So, when you think that if VM is in de-allocated state then I am not charged, YOU ARE WRONG. You are not charged for compute/Cores part; for storage capacity you are charged. However that is too cheap, so don’t worry. Cores are costly and that is where you save cost.
Also if you shutdown Azure VM after taking RDP/ SSH, compute is not released so you are charged for compute and storage both in that case. Therefore, it is recommended that you stop azure vm either using portal or PowerShell command. Refer the FAQ section from link for more details.
Let’s go back to script part now.

Stop multiple Azure VMs script

#define the VM names which are required to be shutdown
$vmNamesToBeShutDown = "vm1", "vm2", "vm3"

foreach($vmName in $vmNamesToBeShutDown)
    $resource = Find-AzureRmResource -ResourceNameEquals $vmName -ResourceType "Microsoft.Compute/virtualMachines"
    if($resource -ne $null)
        Write-Output "Stopping virtual machine..." + $vmName
        Stop-AzureRmVM -ResourceGroupName $resource.ResourceGroupName -Name $vmName -Force
        Write-output "Virtual machine not found:" + $vmName

The variable $vmNamesToBeShutDown is very important. This is where you can add as many VMs as you want to de-allocate them. The only requirement is to add VM name in double quotes and comma separated.
The code then traverse through each of the VM names, checks its existence and if found then fires command to de-allocate the azure vm.

Start multiple Azure VMs script

#define the VM names which are required to be shutdown
$vmNamesToBeStarted = "vm1","vm2", "vm3", "vm4"

foreach($vmName in $vmNamesToBeStarted)
    $resource = Find-AzureRmResource -ResourceNameEquals $vmName -ResourceType "Microsoft.Compute/virtualMachines"
    if($resource -ne $null)
        Write-Output "Starting virtual machine..." + $vmName
        Start-AzureRmVM -ResourceGroupName $resource.ResourceGroupName -Name $vmName
        Write-output "Virtual machine not found:" + $vmName

The structure of the start Azure VM script is same as that of Stop except the command used here to start VM is Start-AzureRmVM.
Here also you will only add VM names comma separated and they will get automatically started once you schedule script running.

Automate and schedule the start/stop Azure VM scripts

Azure automation allows you to create PowerShell script based runbook which can run automatically on pre-defined schedule.
The guidance here is copy paste above scripts in a runbook in PowerShell. When you plan to run the PowerShell as runbook make sure that you are using service principal authentication code at the start of runbook as depicted in this link – http://sanganakauthority.blogspot.in/2017/05/run-login-azurermaccount-to-login.html. The authentication code should be added before any other PowerShell code in runbook. After creating runbook, publish it. Without publish runbook will not execute.
Then create schedule in automation account as per desired schedule. Screenshot below –

Once schedule is created, attach to runbook as below –

Similarly you can create as many as runbook and schedule them at your will and it should work.
Hope this helps.

Happy automating!!

You may be interested in – 

Domain join Azure virtual machine automatically using Azure Automation and DSC - http://sanganakauthority.blogspot.in/2017/01/domain-join-azure-vm-using-azure.html


  1. Nice script. You could also drive it using Tags (Key Value Pairs) added on a particular VM. For instance I've added a tag "AutoSet" = "A" and then using the following PowerShell command will populate a list of VMs from the particular set. You can obviously tweak as required.

    Get-AzureRmVM | Where-Object {$_.Tags.AutoSet -ieq "A"}


    1. Thanks Christiaan. That's also a good idea.