How To: Schedule VM Shutdown using Azure Automation

By Mohamed Radwan

The running of Virtual Machines tends to rely on computing hours, or in another words, it depends on the number of hours that Virtual Machines are running per day.  For example, if you are using Virtual Machines for the West US region, with configuration that includes SSD drive, 2 cores, 7 GB RAM and 100 GB disk, it will cost you $208.32 per month. Microsoft Azure’s website provides a useful pricing calculator which will show you the exact price and configuration of Azure features for your specific setup. Please visit for more details. The use of Virtual Machines with high configuration can work out to be very expensive, however, you can reduce the cost of Virtual Machines by reducing its working hours with Automated Shutdown.

This blog is designed to show you how to create an Automated Shutdown of Virtual Machines on Windows Azure. Included is a step-by-step guide as well as a detailed walkthrough to the process of creating Runbook and Schedule for Virtual Machines and how to link the Runbook to Schedule so that it automatically stops at pre-defined times.

Step 1: Create a new user in Active Directory

PowerShell script is Microsoft's task-based command-line shell and scripting language designed specifically for system administration. In order to run the PowerShell Script with Microsoft Azure, you will need to have a User linked to one of your Directories. If you don’t currently have one, you will need to create one. To do so;

  1. Open the Microsoft Azure Portal and click on ACTIVE DIRECTORY from the navigation pane. Azure Active Directory is a comprehensive identity and access management cloud solution that provides a robust set of capabilities to manage users and groups.
  2. From the list of active directories, we will click on our directory. In our case it is Default Directory.
  3. Under Default Directory, click on USERS.
  4. From the command bar at the bottom of the Portal screen, click on ADD USER.1
  5. A new window named Tell us about this user will appear. In this window, under TYPE OF USER field, choose New user in your organization from the drop down menu.
  6. Under USER NAME field, type an appropriate user name. In our case we will type <PowerShell>.
  7. From the drop down menu choose a domain for this user, in our case we will choose
  8. Click on the arrow to continue.2
  9. On the user profile page, under FIRST NAME and LAST NAME fields, type the respective names. In our case we will type <Power> and <Shell> respectively.
  10. Under the DISPLAY NAME field, type the desired display name which can be different from the user name. In our case, we will keep the display name <PowerShell> which is same as the user name.
  11. Under the ROLE field, from the drop down menu, choose Global Admin. This role has access to all administrative features and is therefore the one who can assign other administrator roles. The person who signs up for the Microsoft Azure account should become the Global Administrator.
  12. Under the ALTERNATE EMAIL ADDRESS field, provide an additional email address that you own. This email address is used for important notifications, including password self-reset, so the user must be able to access the email account regardless of whether the user has access to Microsoft Azure.
  13. Under the MULTI-FACTOR AUTHENTICATION field, do not mark the Enable Multi-Factor Authentication checkbox as this will be used for Automation. Microsoft Azure Multi-Factor Authentication adds an extra verification step to all of your cloud-based applications and services and helps safeguard access to data and applications whilst meeting user demand for a simple sign-in process.
  14. Click on the arrow to continue.3
  15. Next, click on the Get temporary password page, click on create to generate a temporary password which we will need to change later.
  16. The user will be provided with a new temporary password – Yoko9221. We will copy the auto generated temporary password as we will need that for our first sign-in as a new user and in order to change our temporary password.
  17. Click on the arrow to continue.
  18. We can then see a new user within the display name <PowerShell> in the list of USERS under default directory.5
  19. In order to set a new password for New User - <PowerShell>, go to
  20. Login to Office 365. Type the e-mail address of New User, in our case it is < Powershell@mohamed radwanmsfhotmail.onmicrosoft .com> and paste the auto generated Temporary Password, in our case it is Yoko9221.
  21. Click on Sign in.
  22. In the Current Password field, insert the Temporary Password – in our case it is Yoko9221, in the New Password field type an appropriate new password and type it again in Confirm Password field.
  23. Click on Update password and Sign in.

Step 2: Specify a co-administrator for subscriptions

After we have created a New User - <PowerShell>, we need to establish the co-administrator. Prior to November 2010 (the release of Windows Azure SDK 1.3), an Azure subscription had only one system administrator. Since Windows Azure SDK 1.3, the Service Administrator can establish co-administrators. When the subscription is created, only a single Service Administrator can manage the operations of the account.  Co-administrators help manage the services and data running in Windows Azure.

The following email address can be added as a Co-Administrator:

  • Microsoft Account (formerly Windows Live ID) - We can use a Microsoft Account to sign in to all consumer-oriented Microsoft products and cloud services, such as Outlook (Hotmail), Skype (MSN), OneDrive, Windows Phone, and Xbox LIVE.
  • Organizational account - An organizational account is an account that is created under Azure Active Directory. The organizational account address resembles: user@<your domain>.on

Co-administrators have complete access to the subscription services.  They can even add or delete other co-administrators.  However, they cannot remove the Service Owner (the Service Administrator).  Also, co-administrators do not have access to payment/billing information (things managed by the Account Administrator).

  1. Navigate back to Azure Portal and from the navigation pane, click on SETTINGS.
  2. Under settings, click on ADMINISTRATORS.
  3. From the command bar at the bottom of the Portal screen, click on ADD.
  4. A new window Specify a co-administrator for subscriptions will appear. In this window, under EMAIL ADDRESS field, we will type the e-mail address of the person we want to add as co-administrator, in our case we will type: <Powershell@mohamedradwanmsfhotmail.onmicrosoft .com>.
  5. Under the SUBSCRIPTION field, we will select the subscription that we want the co-administrator to access. In our case we will select Visual Studio Ultimate MSDN by marking the checkbox.
  6. Click on check mark after specifying all the fields.7
  7. We can see now that this user account has the role of Co-administrator in chosen Subscription.


Step 3: Add a New Automation Account

Only now that the new user is created and well defined, you can start with creating the Automation Account for your region. Microsoft Azure Automation helps you to automate all of those frequent, time-consuming and error-prone cloud management tasks. The Automation Runbook Gallery puts samples, utilities, and scenario runbooks right at your fingertips, so that you can get up and run quickly with your Automation tasks.

Automation accounts created with the Azure Classic Portal can be managed by both the Azure Classic and Azure Portal and either set of cmdlets. Once the account is created, it makes no difference how you create and manage resources within the account. If you are planning to continue to use the Azure Classic Portal, then you should use it instead of the Azure Portal to create any Automation accounts.

  1. From the navigation pane in Azure Classic Portal, click on AUTOMATION.
  2. From the command bar at the bottom of the Portal screen, click on CREATE.
  3. A new window Add a New Automation Account will appear. In this window, under the ACCOUNT NAME field, type an appropriate account name, in our case we will type <Automation-1>.
  4. Under the REGION field, from drop down menu we will choose our Region, in our case we will choose West Europe. Microsoft Azure is available in 140 countries, and supports 10 languages and 24 currencies. Make sure to choose your Region properly as not all of the services are available in every Regions.
  5. Click on the check mark after specifying all the fields.9
  6. We can see now that our Automation Account - <Automation-1> is created and is listed on the automation.

Step 4: Create Credential Automation Asset

After we have created the Automation Account, we will need to define the Credentials for it before we can create our Runbook to control VM shutdown. A credential is required in order to authenticate the subscription that is hosting the target VMs. The Automation Assets page presents the different Assets, including connections, credentials, schedules, and variables, which are globally available to be used in or associated with a Runbook. The page also contains the commands to import an integration module, add a new Asset, or delete an Asset. An Automation Credential Asset holds the PowerShell Credential object which contains security Credentials such as username and password.

  1. From the automation page, we will click on our Automation Account - <Automation-1>.
  2. Under <Automation-1>, click on ASSETS at the top of the window.
  3. From the command bar at the bottom of the Portal screen, click on ADD SETTING.11
  4. A new window ‘Select the type of setting you want to add’ will appear. In this window, we will see the list of all Assets. Click on ADD CREDENTIAL.

    Credentials are either a username and password combination that can be used with Windows PowerShell commands or a certificate that is uploaded to Azure Automation. The properties for a credential are stored securely in Automation, and can be accessed in the runbook with either the Get-AutomationPSCredential or Get-AutomationCertificate activity.


  5. On the first Define Credential page, which is under the CREDENTIAL TYPE field, from the drop down menu choose Windows PowerShell Credential from the drop down menu.
  6. Under the NAME field, type an appropriate name for Credential Automation Asset, in our case we will type <PowerShell Credential>.
  7. Under the DESCRIPTION field, type an appropriate description for Credential Automation Asset, which will also help us to remember why this Credential is being used, in our case we will type <Use to automate some PowerShell script>.
  8. Click on the arrow to continue.13
  9. On the second Define Credential page, under the USER NAME field, type the email address of the New User that we created < Powershell@mohamedradwanmsfhotmail.onmicrosoft .com>.
  10. Type and confirm the New Password, which we created in Step 1 – Sub Step 22.
  11. Click on the check mark after specifying all the fields.14
  12. We can see that our Credential Automation Asset - <PowerShell Credential> is now created which we will be using to run some Runbooks.15

Step 5: Create a Runbook

After we have added Credential Automation Asset - <PowerShell Credential>, we can finally create our Runbook, which is actually nothing more than a PowerShell script encapsulated in a Workflow object that helps us to work smarter by handling the creation, deployment, monitoring, and maintenance of Microsoft Azure resources and third-party applications. In short, Runbook is a set of tasks that perform some automated process in Azure Automation. The Microsoft Azure Portal provides two basic methods to create a new Runbook: Quick Create and From Gallery. In this case we will use the From Gallery Method.

  1. On Automation Account - <automation-1> page, click on RUNBOOKS.
  2. From the command bar at the bottom left of the Portal screen, click on NEW.
  3. A pop up window will open up, on which we will click on RUNBOOK.
  4. Under RUNBOOK options, click on FROM GALLERY.16
  5. On the Select a runbook page, we can filter to select runbooks authored by MICROSOFT or the COMMUNITY and by POWERSHELL WORKFLOWS or POWERSHELL SCRIPTS. In our case we have filtered by POWERSHELL SCRIPTS as seen on the bottom left of the screen. On Select a runbook screen, we will notice that there are almost 200 pre-configured runbooks to choose from. Click on VM Lifecycle Management on the left of the screen as we are looking for the runbook that will stop all virtual machines and this runbook can be found in VM Lifecycle Management.
  6.  Under the VM Lifecycle Management options, click on Azure Automation Workflow to Schedule stopping of all Azure Virtual Machines in the centre column to schedule stopping of all Azure Virtual Machines.
  7.  Click on the arrow to continue.17
  8. On the Review runbook definition page, we can read the information provided about the runbook and then decide if it meets our needs. If the runbook isn’t what we want, click the left arrow to go back to select a different runbook.
  9. Click on the arrow to continue.18
  10. On the Enter runbook details page, under the RUNBOOK NAME field, we will modify the default name of the runbook - Stop-AllAzureVM to <Stop-AllAzureVM-RunBook>.
  11. Choose the Automation Account - <Automation-1> and the Subscription – Visual Studio Ultimate MSDN. The REGION field autopopulates with the region that corresponds to the subscription
  12. Click on the check mark after specifying all the fields.19
  13. We can see now that our Runbook - <Stop-AllAzureVM-RunBook> is created with PowerShell Script which will stop the Virtual Machine.


Step 6: Add a Schedule for Runbook

After we have created a Runbook - <Stop-AllAzureVM-RunBook> that includes PowerShell Script, which will stop the Virtual Machine, we need to create a Schedule to execute the runbook automatically at either a specific date and time or on a recurring basis. No manual intervention is necessary to start schedule assets.

Although schedules are assets, they differ slightly from assets such as connections, certificates and variable assets. The difference is that we never insert or call a schedule from script code. Rather we will link a runbook to a schedule. A schedule asset determines when runbooks that are linked to it can run. A schedule asset triggers runbook execution when the schedule is activated. We select a published runbook, and on its Schedule tab, we can choose to link to a new schedule. Draft runbooks cannot be linked to a schedule.

Schedule assets are the alternative for manual invocation of runbooks or being called by code from another runbook. Scheduling is just a deeper level of automation beyond just having a script: It’s like automating the automation!

  1. On Automation Account - <automation-1> page, click on ASSETS.
  2. From the command bar at the bottom of the Portal screen, click on ADD SETTING.
  3. A new window Select the type of setting you want to add will appear. In this window, we will see the list of all Assets. Click on ADD SCHEDULE.21
  4. On the first Configure Schedule page, under the NAME field, type an appropriate name for Schedule Asset, in our case we will type <Stop-VM-Schedule>.
  5. Under the DESCRIPTION field, type an appropriate description for Schedule Asset, such as why this schedule is being used or some other additional information, in our case we will type <Stop-VM-Schedule description>.
  6. Click on the arrow to continue.22
  7. On the second Configure Schedule page, under the TYPE field, we can choose to run the schedule ONE TIME, HOURLY or DAILY. In our case we will choose DAILY. Depending on the option we select, the remainder of the dialog box entry fields will change slightly.
  8. Under the START TIME field, choose a start date and time, in our case we will choose <2015-09-07 & 23:59>. As an option we can select the SET SCHEDULE EXPIRATION TIME check box and then enter a date and time to ensure the schedule expires at that date and time. We can also enter our desired value in the RECUR EVERY (NUMBER OF DAYS)
  9. Click on check mark after specifying all the fields.23
  10. We can see now that our Schedule Asset - <Stop-VM-Schedule> is created and is listed on our Automation Account - <automation-1> page, which will be used to execute the Runbook - <Stop-AllAzureVM-RunBook> automatically.24

    Step 7: Test and Publish the Runbook

    Before we promote a runbook to a published state, we need to test it to ensure that it’s ready to use. A test run of a runbook still runs all the code and does what it needs to do in reality. We can use test assets or parameters that contain test environment information and point to the test environments. When the runbook is ready to be published, we can switch them into a runtime environment.

    We will promote a runbook from draft status into a publish status after it is tested and we are sure it works correctly. If later we want to go back and modify it, we can toggle it back into Draft mode, edit it, and then publish it again from the Author pane in the Azure Management Portal. While we are editing a runbook, the published version will be the version called schedules or cmdlets. This allows us to edit while the published version runs.

    1. On Automation Account - <automation-1> page, click on RUNBOOKS.
    2. Click on the Runbook that we want to test and publish, in our case it is <Stop-AllAzureVM-RunBook>.
    3. Under <stop-allazurevm-runbook> page, click on AUTHOR at the top of the window. This will put the runbook automatically into draft mode for the version we are editing. A best practice when authoring runbooks is to write granular and single tasks so we can then reuse and insert them later (after they are published) in other runbooks.25
    4. Now in default script we will fill in the -Name parameter with the name of the Automation PSCredential asset that has access to our Azure subscription. In our case <PowerShell Credential> is the credential asset that will be used to authenticate with Azure AD, so in line 32 replace the text myPSCredName with PowerShell Credential. The Windows PowerShell workflow code makes a call to the Get-AutomationPSCredential cmdlet to authenticate the script.
    5. The Get-AutomationPSCredential action returns a credential object that is immediately passed in the call to Add-AzureAccount. The Add-AzureAccountactivity then uses this credential to provide authentication for any activities that come after it.
    6. Now in order to test the credential, we will cut all the rows till the end of the script (from line 37 to line 64) and copy them to the clipboard as we will need them later.26
    7. Type Write-Output $Cred in line 36 to test the credential. The Write-Output cmdlet sends the specified object down the pipeline to the next command. If the command is the last command in the pipeline, the object is displayed in the console.
    8. From the command bar at the bottom of the Portal screen, click on TEST to run the code and to see the output.
    9. Once it is completed, we will receive output in the OUTPUT PANE displaying basic information from our account. This confirms that the credential is valid.27
    10. Now that we have successfully tested the credential and we have seen the output in the OUTPUT PANE, we will remove Write-Output $Cred from line 36.
    11. Then, paste all the rows that we cut previously in Step 7 – Sub Step 6 (from line 37 to line 64) in the Script.28
    12. Now in default script we will fill in the -SubscriptionName parameter with the name of our Azure subscription. In our case <Visual Studio Ultimate with MSDN> is the subscription that we want to work against, so in line 39 replace the text Some Subscription Name with Visual Studio Ultimate with MSDN.
    13. Now the default script will stop each VM and we don’t want to stop all virtual machines. We want to run the domain controller or at least one machine all the time. The domain controller is the hardware configuration used the least so we will let this run all the time as this also could help us to preserve the IBs for the whole services. So we will just change the script a little bit and will add an “if condition” - < If ($vm.ServiceName -ne ‘domain-mra’) > in order to keep domain controller running all the time.
    14. From the command bar at the bottom of the Portal screen, click on TEST to run the code and see the output.29
    15. Once it completes, we will receive output in the OUTPUT PANE and we will check that all the virtual machines were stopped and domain controller – Domain-mra was still running to ensure that the script is running properly.31
    16. We will save the script now as we have tested that it is running properly. In order to save the Draft Script, navigate back to AUTHOR pane under < stop-allazurevm-runbook > and from the command bar at the bottom of the Portal screen, click on the SAVE button.
    17. The runbook that we just saved is still in Draft mode. A runbook needs to be published to be started as we can’t start a runbook in Draft mode. When we publish a runbook, we overwrite the existing Published version with the Draft version. In our case, we don't have a Published version yet because we have just created the runbook. All draft runbooks can run only in Test mode. To Publish the Draft Script, from the command bar at the bottom of the Portal screen, click on the Publish button.
    18. Navigate back to the RUNBOOKS pane under < automation-1 > to see the Published Runbook.
    19. We can see now that the Runbook - < Stop-AllAzureVM-RunBook > is published and in this case the Job Status is marked as none as the Runbook hasn’t run yet.33

    Step 8: Link the Runbook to an Existing Schedule

    Now that we have published the runbook to stop a virtual machine, we need to link it to a schedule, so the runbook stops automatically when we want it to. We can link one or even more Schedules to one Runbook.

    1. In the Automation Account, which in our case is < automation-1 >, we will click on the runbook that we want to link to the schedule, which for us is to < Stop-All AzureVM-Runbook >.34
    2. Under < stop-allazurevm-runbook > page, click on SCHEDULE.
    3. In our case we don’t have a Schedule linked to our Runbook yet. We can create new Schedule from this point and link it to the Runbook or we can link it to an existing Schedule. We will click on LINK TO AN EXISTING SCHEDULE.
    4. A new window, Select a schedule will appear. In this window we will see the list of all existing Schedules. Select < Stop-VM-Schedule >, that we created in Step 6.
    5. Click on the check mark after selecting the schedule.35
    6. We can see now that the Runbook - < Stop-All AzureVM-Runbook > is linked to the Schedule - < Stop-VM-Schedule >. We can also see when the next run is scheduled and if the Schedule is enabled or not.36


    The Microsoft Azure Portal provides different, basic techniques to create and manage Virtual Machines in the Microsoft public cloud. With Automation service, we can save time and money, eliminate time-consuming, repetitive tasks and improve quality and efficiency by minimizing manual work and human errors. For Automation we can use already integrated PowerShell Scripts, which allows us to run our Automation tasks quickly. If we would like to use Virtual Machines just for office hours, the Automation is a great solution. If we take the example configuration of Virtual Machine from the introduction, that would cost us $208.32 per month. However, if we were to use it only for office hours (i.e. 8 hours per day, only weekdays) our cost would only be $47.04. This represents almost 80% of savings, which is a fantastic result.

    Radwan-MVP-252-275By Mohamed Radwan. Mohamed is a Visual Studio ALM MVP and DevOps practice lead at Testhouse; he focuses on providing solutions for the various roles involved in software development and delivery to enable them to build better software through Agile Methodologies and utilization of Microsoft Visual Studio ALM/DevOps Tools & Technologies.   He has helped various customers across the world in the UK, Denmark, USA, Egypt, Oman, KSA, Kuwait, and Libya, amongst others.  He has authored several frameworks and extensions including DevMagicFake and TestingConf Utilities, as well as many technical articles & guides. He is the founder of the TFSEG and co-founder of the MEAALM Community.  Mohamed also holds a number of Microsoft certifications including MCT, MCPD, MCITP in EPM, MCTS (7), MCSD, MCAD, and CIW.

Comments (3)
  1. You’re missing the major problem that the user account created has a password expiry of 90 days. After 90 days, the password expires and the schedule stops working. Fixing this involves a load of PowerShell (wouldn’t you just guess that).
    Be great if you could add this extra step so that the documentation of how to do this is all in one place.

  2. Harj says:

    I’m trying to run this script, but the line below never comes back with any VMs even though I have one running?

    $VMs = Get-AzureVM | where-object -FilterScript {$_.status -ne ‘Stopped(Deallocated)’}

  3. Steven Edouard says:

    Hey there!

    If anyone else is till looking for this functionality VMPower ( offers Azure scheduled VM startup/shutdown as well as shutdown based on network/cpu/disk utilization. There’s a free tier if your VM isn’t too big otherwise it might make sense with their pricing model if you work out your potential savings based on the pricing calculator.

Comments are closed.

Skip to main content