Skip to content

Automatic Azure VM resizing

Automatic Azure VM resizing

People who know me know that I often cut costs for my Azure services in a variety of ways. Automatic resizing of VM (virtual machines) was one of the first cost savings I used. It has good and bad sides, after 3 years of testing I will try to tell you more about them.

So it started with the fact that if we have a lot of cloud servers and they are expensive, it would be good to lower the cost of maintaining them.

A certain group of servers were used intensively between 7:00 a.m. – 5:00 p.m. and outside of these hours you could say the machines were boring. The problem was that the servers could not be turned off because the services had to be available all the time.

Here, a great way to cut costs is to resize the VM. We just don’t want to do it manually, because every time after finishing the work, you would have to reduce the size, and in the morning before starting the work, you would have to increase the size.

vm size azure

We can use, for example, the Azur “Automation Account” to automate this process.

vm size automation azure blog

We create a new “PowerShell” runbook in it, add a name and description to it, so that we know what it is in the future.

vm size create runbook
vm size runbook azure blog

In the Runbook, we give the Resource Group name where our VM is, name our VM and size specified by us.

$ResourceGroupName = "Resource_group_name"
$VMname = "VM_name"
$Size = "Standard_F1s"

$vm = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname -Status
$vm = $vm.Statuses.DisplayStatus | Select-String -Pattern "VM running"

if($vm -match "VM running")
{
Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname -Force
$vm1 = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname
$vm1.HardwareProfile.VmSize = $Size
Update-AzureRmVM -VM $vm1 -ResourceGroupName $ResourceGroupName
Start-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname
}

If the machine is running, a script to resize it will be executed. If the VM is turned off, there is no need to resize it, because we don’t pay any additional charges for the turned off machine, except for the disks of course.

So the script stops the VM, changes its parameters (size) and starts it.

Now you just need to save our runbook and specify the time of the script execution. We do it using the “Add a schedule” option.

vm size azure schedule cloud

Then we need to create the same script again, only change the size and runtime to be executed before starting work, not after its completion.

The upside is that we save money. The smaller the size of the machine, the less it costs. If we have a large number of machines or machines with large dimensions, you can really save a lot.

The downside is that sometimes the machine gets stuck in a “deallocated” state, for example when some data center is out of resources or has some technical problems. Such a situation happened literally several times in these 3 years, but it is worth keeping in mind.

Therefore, I introduced an additional condition that the machine can only change size when the previous one, which was being resized, has the “running” status. We can easily check it, for example:

#if VM1 is "running" then execute the script
$sprawdz_VM = "Nazwa_wcześniej_zmienianej_VM"
$sprawdz_RG = "Nazwa_ResourceGroup_wcześniej_zmienianej_VM"

$VMStats = (Get-AzureRmVM -Name $sprawdz_VM -ResourceGroupName $sprawdz_RG -Status).Statuses

$VMStats= ($VMStats | Where Code -Like 'PowerState/*')[0].DisplayStatus

if ($VMStats  -eq "VM running")
{
PLEASE INSERT THE SCRIPT FROM THE SIZE HERE
}

Finally, I give the entire content of the runbook:

$DateTimeNow = Get-Date
if($DateTimeNow.DayOfWeek -ne "Saturday" -and $DateTimeNow.DayOfWeek -ne "Sunday") 
{
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} 
else
{
 Write-Error -Message $_.Exception
throw $_.Exception
}
}



$sprawdz_VM = "Nazwa_wcześniej_zmienianej_VM"
$sprawdz_RG = "Nazwa_ResourceGroup_wcześniej_zmienianej_VM"

$VMStats = (Get-AzureRmVM -Name $sprawdz_VM -ResourceGroupName $sprawdz_RG -Status).Statuses
$VMStats= ($VMStats | Where Code -Like 'PowerState/*')[0].DisplayStatus

#jeśli poprzednia maszyna VM1 ma stan "running" to wykonaj skrypt
if ($VMStats  -eq "VM running")
{
$ResourceGroupName = "Nazwa_resource_group"
$VMname = "Nazwa_VM"
$Size = "Standard_F1s"

$vm = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname -Status
$vm = $vm.Statuses.DisplayStatus | Select-String -Pattern "VM running"

# jeśli maszyna której chcesz zmienić rozmiar ma stan "running" to wykonaj skrypt 
if($vm -match "VM running")
{
Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname -Force
$vm1 = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname
$vm1.HardwareProfile.VmSize = $Size
Update-AzureRmVM -VM $vm1 -ResourceGroupName $ResourceGroupName
Start-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname
}
}

More information on the Automation Account can be found, as usual, in the Microsoft documentation https://docs.microsoft.com/en-us/azure/automation/automation-intro

More information on the sizes of virtual machines can be found at: https://docs.microsoft.com/en-us/azure/virtual-machines/sizes

If you would like to know more ways to save money on Azure, I invite you to my other entries in the Azure category.

6 thoughts on “Automatic Azure VM resizing”

  1. Hi. I seem to be stuck with this. It does everything except the resize. It powers it off and on again but doenst resize. The log shows “‘Vhd’ cannot be null.” When i try it direct in cloud shell it works fine…
    Any idea?

    1. Hi. Check if you provide the correct size of the VM, check the list of available sizes:
      az vm list-vm-resize-options –resource-group ResourceGroup_NAME –name VM_NAME –output table

      Maybe a typo, it’s hard to advise without seeing the code.

      ——-
      You can check for example:
      #dealocate
      az vm deallocate –resource-group ResourceGroup_NAME –name VM_NAME
      #resize
      az vm resize –resource-group ResourceGroup_NAME –name VM_NAME –size Standard_DS3_v2

  2. Is it possible Sacle Down size of vm at night & Again scale up Vm size to deafault in Morning.
    VM size will Scale up & down in night & morning
    Is their any automation script

    1. Yes you can use the script from this article 2 times. Once you set the automatic start in the morning with a large size (scaling up) and in the evening you set the automatic start with a smaller VM size (scaling down).
      If you do not want to use automation account, you can use the commands from this script and execute them somewhere else, just remember about the necessary permissions.

  3. THX for the inspiration. As Azure is agile it is worth to mention the scripts need adjustment:
    #1 RunAsUser is deprecated so use Managed Identity instead, see also sample scripts:
    #2 XY-Stop-AzureRmVM is replaced by xy-AzVM, e.g. Update-AzVM -ResourceGroupName $FuncRGName -VM $FuncVM
    Ad #1: use managed identiy:
    try {
    “Logging in to Azure…”
    Connect-AzAccount -Identity
    }
    catch {
    Write-Output (“Please enable appropriate RBAC permissions to the system identity of this automation account. Otherwise, the runbook may fail…”)
    Write-Error -Message $_.Exception
    throw $_.Exception
    }
    Ad #2 sample Resizing
    $NewSize = “Standard_F1s”
    Stop-AzVM -ResourceGroupName $RGName -Name $VMName -Force
    $VM = Get-AzVM -ResourceGroupName $RGName -VMName $VMName
    $VM.HardwareProfile.VmSize = $NewSize
    try {
    Update-AzVM -ResourceGroupName $FuncRGName -VM $VM
    }
    catch {
    Write-Output (“Error resizing …”)
    }
    Start-AzVM -ResourceGroupName $RGName -Name $VMName
    $CurSize = (Get-AzVM -ResourceGroupName $RGName -VMName $VMName).HardwareProfile.VmSize
    if ($CurSize -ne $NewSize) {
    Write-Output (“Error: still at size $CurSize”)
    }

  4. Yes, you are right, I wrote this article a some time ago and the cloud world is changing fast. Thank you very much for your update. I’ll try to look at this and other articles in the near future and update them.

    Thanks again for your comment, I’m sure it will be useful to many people

Comments are closed.