Azure Automation: How to stop/start Azure VM on schedule


To be cost-effective in any cloud-based environment you have as an option to shut down your VM in off-hours. In the Microsoft Azure IaaS you can stop (deallocate) and start your VMs on schedule with Automation Accounts.


Apply-AzVmPowerStatePolicy.ps1 script

  • With a PowerShell script Apply-AzVmPowerStatePolicy.ps1 from my Azure repo you will be able to build your own Runbook and schedule stop/start for your Azure IaaS VMs.

  • All you need is to create two Resource Tags named PowerOn and PowerOff and set them for each VM that you want to schedule. We will automate it later.


  • Only VMs that have both tags set will have a part of scheduling process. If you plan to schedule start or stop only for specific VM there are flag values for both Tags.

  • If PowerOn Tag equal to 11:11:11 a VM will not start on schedule.

  • If PowerOff Tag equal to 22:22:22 a VM will not stop on schedule.

  • To automate Tag set you can utilize two functions Get-AzVmTag/Add-AzVmTag from my Az-Module.

Import-Module Az-Module
Get-Command -Module Az-Module -Noun *tag
Get-Help Get-AzVmTag -Full
Get-Help Add-AzVmTag -Examples


  • The Apply-AzVmPowerStatePolicy.ps1 script written as PowerShell Workflow to support parallel VM processing. Unfortunately, Start-AzureRmVm and Stop-AzureRmVm cmdlets do not support asynchronous running on multiple VMs at this moment Emoj and we will need to move this functionality to the script itself.

Automation Account Resources

  • After you have set tags for all your desired VMs you are ready to start with the Automation Account Resources.


  • You really have to create three resources only: Runbook, Credentials Asset and Schedules Asset with parameters.

Let’s start in the order.

Step 1: Runbook

  • Add new Runbook of PowerShell Workflow type. The right runbook type is a super important step!

  • Requirement: The Runbook name must be the same as Workflow name within the Apply-AzVmPowerStatePolicy.ps1 script (Workflow Apply-AzVmPowerStatePolicy { } in our case). If you did not like this name Emoj, rename the Workflow to match your Runbook name.


  • Other Runbook types have different icons to distinguish one from another.


  • Edit the Runbook and paste into CMDLETS area all script content.


Step 2: Credentials Asset



Step 3: Schedules Asset

  • Add new Schedules Asset for your Runbook.


  • The Schedules Asset contains not only schedule plans themselves, it contains more important thing – the script parameters!

  • As you can see the Apply-AzVmPowerStatePolicy.ps1 script has five parameters.



Parameter Description
AzureCredentialAsset Credential Asset name, created in Step 2
AzureSubscription Target Subscription (Get-AzureRmSubscription)
AzureResourceGroup VM ResourceGroup (Get-AzureRmResourceGroup)
AzureVmTimeZone VMs Time Zone
WhatIf Execute or simulate execution
  • All the parameter names are self-explained. Is to say only about two of them: -AzureVmTimeZone and –WhatIf.

  • -AzureVmTimeZone – is your VMs’ Time zone. The stop/start time in the PowerOn/PowerOff VM tags is set in this time zone local time!

  • To get list of existing time zones across the world run this command on your computer.

[System.TimeZoneInfo]::GetSystemTimeZones() | Format-Table –AutoSize
[System.TimeZoneInfo]::GetSystemTimeZones() | ? {$_.DisplayName -match 'canada'}

Take the Id property for your time zone.

  • -WhatIf – is a Boolean parameter. The default is $true (to simulate power on/power off). If you want to actually execute stop/start process, set it to $false.


  • Each Runbook execution creates a job. After the job is completed you can view the job statistics in Errors, Warnings, All Logs and Output tiles.


  • Click on the Output tile and you will find here all your VMs report. Pay attention to the StatusCode property. It can be OK, Error or blank when StatusChange property equal to NotRequired.

  • If you got an Error then check PowerOn and PowerOff properties, probably one of them or both either not set or cannot be considered as [datetime] value.




  • If you are already have downloaded my Azure Automation Az-Module, this one-liner will help you to retrieve PowerOn/PowerOff tags for all VM in a ResourceGroup.
Get-AzureRmVm -wa SilentlyContinue -ResourceGroupName (Select-AzResourceGroup) | Get-AzVmTag -Tags 'PowerOn', 'PowerOff'
  • With this one-liner you can get VM PowerState.
Get-AzureRmVm -wa SilentlyContinue -ResourceGroupName (Select-AzResourceGroup) | Get-AzVmPowerState
Get-AzureRmVm -wa SilentlyContinue | Get-AzVmPowerState
Get-AzureRmVm -wa SilentlyContinue -ResourceGroupName (Select-AzResourceGroup) | Get-AzVmPowerState -State NotRunning
Get-AzureRmVm -wa SilentlyContinue -ResourceGroupName (Select-AzResourceGroup) | Get-AzVmPowerState Running

You may also like:

Azure Automation PowerShell Az-Module Home

13 thoughts on “Azure Automation: How to stop/start Azure VM on schedule

      1. Well , don’t understand reply, you just confirmed it does need a runbook for each Resource Group unless you make a iterative loop that reads and feeds resource group to build your $AzVm, becaue each time you setup a sceduel to run you need to specify the RG parameter and you only have 1 chopice , so if you have 2 VMS, one in RG A one in RG B you need to make to runbooks for each RG , yes? Unless of course you do as I said modify workflow. What am I missing. Anyhow I tried both ways unable to get her to work.


      2. Each time a Runbook runs on one ResourceGroup, but… You can create several Schedules Assets under same ResourceGroup. As stated in the article, namely a Schedules Asset contains the script parameters and one of them is what you need -AzureResourceGroup (target ResourceGroup where your VM are living). Did you try to forcibly run your Runbook with no Schedule (Start button at the top of the page in the Portal) ?


  1. Code fails to account for all timezones. For example in New Zealand Standard Time, it takes the powerOn and Of times and creates a datetime object in the UTC timezone. Therefore when you compare you can hit edge conditions where the date component is out by a day, thereby faliing the tests to determine correct PowerState Change.
    I’ve Forked the Git repo and updated it to compare just the TimeOfDay property of the DateTime objects to resolve.

    Also the PowerOn / off tags appear to need seconds, so 18:00 was failing, but 18:00:00 was working.


    1. Hi Bryn,

      The Azure time is UTC, always.
      To compare your Time zone local time with the Azure time I decided to convert the Azure time to your local time.
      It was possible vice versa also. For example, if 06:00 PM in the Azure, in the New Zealand is:

      [System.TimeZoneInfo]::ConvertTimeFromUtc([datetime]'18:00', [System.TimeZoneInfo]::FindSystemTimeZoneById('New Zealand Standard Time'))

      About the Tags, you needn’t the seconds, the [datetime] datatype converts short time successfully too. Try it yourself:


      Regarding to the PowerState, what error do you get? Did you try to run the script outside the Runbook?


    1. The article was written almost two years ago and at the time of writing this item did not yet exist.
      In addition, the behavior of the Azure marketplace items would change and you can not control it and know about it.
      And finally, the purpose of my articles is purely educational, if the material turns out to be also useful, so say thanks and leverage it for free.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s