Schedule Scale up/down VMs with Azure Automation

  • May 13, 2019

I recently got a request from one of our customers who have an ERP system where they experience slowness due to high load the first monday and tuesday of every month. They wanted us to implement a scheduled scaling of the machine. As this is a single VM we could only scale up/down by changing the VM Size. The drawback is that this requires a reboot, but as long as you’re aware of the necessary downtime and setup your schedules outside office hours this can be solved easily with Azure Automation

Powershell Runbook

<#
    .SYNOPSIS
        This Azure Automation runbook use tags to scape up/down a virtual machine

    .DESCRIPTION
        This runbook will resize a virtual machine based on the tags attached to the Virtual Machine object. Both 'ScaleUpSize' and 'ScaleDownSize'-tags must be present for scaling to work.

        The runbook is ment to be run on two different schedules:
        1. Set 'SCALEUP'=$true to resize a VM to the size set in 'ScaleUpSize'
        2. Set 'SCALEUP'=$false to resize a VM to the size set in 'ScaleDownSize'

        The runbook assume the Automation account is created with a 'Azure Run as Account'

    .PARAMETER RG
        The Resource group where the Virtual Machine is located

    .PARAMETER VM
        The name of the Virtual Machine to be scaled

    .PARAMETER SCALEUP
        The parameter acts as a switch. If set to 'True', the VM will be scaled up. If 'False' the VM is scaled down.
        Default value is 'False'.
#>

param(
    [parameter(Mandatory=$true)]
    [String] $rg,
    [parameter(Mandatory=$true)]
    [String] $vm,
    [parameter(Mandatory=$false)]
    [bool] $scaleUp=$false
)

try
{
    $connection = Get-AutomationConnection -Name 'AzureRunAsConnection'
    Add-AzureRmAccount `
        -ServicePrincipal `
        -TenantId $connection.TenantId `
        -ApplicationId $connection.ApplicationId `
        -CertificateThumbPrint $connection.CertificateThumbprint | Out-Null
}
catch
{
    if (!$connection)
    {
        $errorMessage = "Connection not found"
        throw $errorMessage
    }
    else
    {
        Write-Error -Message $_.Exception
        throw $_.Exception    
    }
}

if($scaleUp) {
    $scaleTagSwitch = 'ScaleUpSize'
}
else
{
    $scaleTagSwitch = 'ScaleDownSize'
}

$vmdetails = Get-AzureRmVM -ResourceGroupName $rg -Name $vm
$scaleSize = $vmdetails.Tags[$scaleTagSwitch]
$vmSize = $vmdetails.HardwareProfile.VmSize
if(($vmSize -ne $scaleSize) -and ($scaleSize))
{
    Write-Output "Resource Group=$rg, Virtual Machine=$vm, Size=$vmSize, ScaleTagSwitch=$scaleSize"

    $vmState = Get-AzureRmVM -ResourceGroupName $rg -Name $vm -Status
    if($vmState.Statuses[1].DisplayStatus -eq "VM running")
    {
        Write-Output "$vm is running. stopping…"
        Stop-AzureRmVM -ResourceGroupName $rg -Name $vm -Force | Out-Null
    }

    $vmdetails.HardwareProfile.VmSize = $scaleSize
    Update-AzureRmVM -ResourceGroupName $rg -VM $vmdetails | Out-Null
    Start-AzureRmVM -ResourceGroupName $rg -Name $vm | Out-Null
    Write-Output "Resized $vm to $scaleSize"
}