Resize Azure Virtual Machines in Parallel

Imagine you had to resize a whole bunch of VMs in Azure, rather than doing a resize one after the other in serial, you can do this in parallel with the new ForEach-Object Parallel feature in PowerShell v7. More details on this feature here – https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/

Doing this in parallel will greatly speed up the process by resizing any number of VMs all at once. To start with, you will need a CSV file with two columns, vmname,targetsize. Enter all the VM names of the VMs that you want to resize, also the correct VM size. 

Sample CSV file:

vmname,targetsize
VM01,Standard_DS14_v2
VM02,Standard_DS14_v2

To get a list of Azure VM sizes and the correct format for the name, run the following:

(Get-AzVMSize -Location 'Australia East').Name

This script will loop through all the VMs in the CSV file, shutting down the VM first before the resize happens. A full shutdown of the VM ensures that all target VM sizes are on offer across all Azure clusters, not just VM sizes of the current cluster in which your VM is a member of. First the script will get the status of the Private IP Allocation Method for the VM (Static or Dynamic) and if the private IP address is Dynamic, it will change it to a Static private address temporarily to make sure that the VM’s private address stays the same while it’s in a shut down state. Then after the resize happens, the VM is powered back up and if the Private IP Allocation Method was changed to Static part of this process, then it changed back to Dynamic, to keep the VM the same as it was originally. 

The full script can be found below and here, be sure to read the lines at the top to make sure you gave the correct version of PowerShell v7 and the correct version of the Az (Azure) PowerShell module. 

<#
Written with PowerShell v7.0.1 – install available here https://github.com/PowerShell/powershell/releases
Written with version 4.2.0 of the Az PowerShell Module
available from here https://github.com/Azure/azure-powershell/releases/tag/v4.2.0-June2020 or run: Install-Module -Name Az -RequiredVersion 4.2.0 -AllowClobber
Migration instructions Azure.RM to Az – https://azure.microsoft.com/en-au/blog/how-to-migrate-from-azurerm-to-az-in-azure-powershell/
#>
##########################################################################################
############################ Logon to Microsoft Azure #############################
##########################################################################################
$AzContextPath = "$($env:TEMP)\$(Get-Date Format yyyyMMdd)AzEnv.json"
#region Logon to Azure | @marckean
Connect-AzAccount Tenant '72f988bf-86f1-41af-91ab-2d7cd011db47'
##################### Subscription Select #####################
$subscriptions = Get-AzSubscription
$cnt = 1
Write-Host "ID Subscription Name"
Write-Host "———————–"
foreach ($sub in $subscriptions){
Write-Host "$cnt $($sub.name)"
$cnt++
}
$selection = Read-Host Prompt "Select a subscription to deploy to"
$subSelect = $subscriptions[$selection 1] # Revert 1-index to 0-index
Select-AzSubscription $subSelect.SubscriptionId
Save-AzContext Path $AzContextPath Force
#endregion
##########################################################################################
################################ List of VM sizes #################################
##########################################################################################
# Get a list of VM sizes, so you know exactly the format of the name:
(Get-AzVMSize Location 'Australia East').Name | Select-String 'DS14'
##########################################################################################
############################# List of VMs to re-size ##############################
##########################################################################################
#region List of VMs to re-size | @marckean
########### Only do one of two options here ###########
# Option 1: Pull VMs from a .CSV file – two columns, headers (vmname,targetsize) | @marckean
$VMs_to_resize = Import-Csv Path 'W:\VMs_to_resize.csv'
# Option 2: Pull VMs from a comma separated here string – this is practically a mini CSV file anyway | @marckean
$VMs = @'
vmname,targetsize
Hadoop01,Standard_DS14_v2
Hadoop02,Standard_DS14_v2
'@
$VMs_to_resize = $VMs | ConvertFrom-Csv
#endregion
##########################################################################################
################################ Resize the VMs ###################$##############
##########################################################################################
$VMs_to_resize | ForEach-Object Parallel {
Import-AzContext Path $using:AzContextPath
# Set private IP address to static to not loose it
$NicID = ((Get-AzVM Name $_.vmname).NetworkProfile.NetworkInterfaces[0].Id)
$Nic = Get-AzNetworkInterface ResourceId $NicID
$PrivateIpAllocationMethod = $Nic.IpConfigurations[0].PrivateIpAllocationMethod # Remember original Private IP Allocation Method
If($PrivateIpAllocationMethod -eq 'Dynamic'){ # only change the IP addess to static it's Dynamic
$Nic.IpConfigurations[0].PrivateIpAllocationMethod = 'Static'
Set-AzNetworkInterface NetworkInterface $Nic}
Write-Output "$($_.vmname) is currently set as $PrivateIpAllocationMethod"
# Stop deallocate, resize the VM
$vm = Get-AzVM Name $_.vmname
$VMsize = $_.targetsize
Write-Output "Change $($_.vmname) to $VMsize"
$vm | Stop-AzVM Force
$vm.HardwareProfile.VmSize = $VMsize
Update-AzVM VM $vm ResourceGroupName $vm.ResourceGroupName
$vm | Start-AzVM
# Changing the Private IP address allocation method of a running VM to Dynamic using PowerShell doesn't cause a restart
If($PrivateIpAllocationMethod -eq 'Dynamic'){ # only change the IP addess back to Dynamic it was Dynamic in the first instance
$Nic = Get-AzNetworkInterface ResourceId ((Get-AzVM Name $_.vmname).NetworkProfile.NetworkInterfaces[0].Id)
$Nic.IpConfigurations[0].PrivateIpAllocationMethod = 'Dynamic'
Set-AzNetworkInterface NetworkInterface $Nic}
}

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com 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