Using PowerShell with Azure VM. Sometimes you need to change something on a VM. You may want to rename it for compliance reasons, change the network, change the disk name, etc
Once you create a VM in Azure there is no way to rename it or one of its components. Also, if you want to reconnect a VM to a different Virtual Network, you can’t. You can look in the portal, you can search the Azure PowerShell Cmdlet list or try with AZ CLI, you can’t.
Some will say that you can use a backup vault to recreate the VM but it takes times and it doesn’t scale. You can’t manage multiple VM like this.
We can automate this with PowerShell and the Azure PowerShell module.
Imagine if you need to rename a VM and its disk in the same resource group and the same Azure region
The first step is to create an object with the current VM configuration
$SourceVmObject = get-azvm -Name dsc-dns01 -ResourceGroupName MyRG
$SourceVmObject = get-azvm -Name dsc-dns01 -ResourceGroupName MyRG
$SourceVmObject = get-azvm -Name dsc-dns01 -ResourceGroupName MyRG
If the VM uses Azure Backup Vault, before continuing we need to remove the VM’s recovery point.
When you create a Backup Vault, Azure will add an extra resource group named AzureBackupRF_RegionName_1, there is nothing visible inside (if you use the portal), but this where you can find the VM recovery point.
There are named after the VM name, AzureBackup_vmname_XXXXXXX and it needs to be deleted before any copy operation on the VM.
The problem is that it may fail sometime and you may need to do it again.
$LoopCondition = $false
$Count = 0
do {
try {
Remove-AzResource -ResourceId $SourceVmRecoveryPoint.ResourceId -Force
$LoopCondition = $true
}
catch {
write-debug "Fail to delete recovery point $($SourceVmRecoveryPoint.Name) after $($Count) attentds"
}
$count +=1
if ($count -gt 5) {
$LoopCondition = $true
}
} until ($LoopCondition)
We need to make sure the VM is deallocated.
$SourceVmPowerStatus = (get-azvm -Name $SourceVmObject.Name -ResourceGroupName $SourceVmObject.ResourceGroupName -Status).Statuses | where-object code -like "PowerState*"
if ($SourceVmPowerStatus -ne "VM deallocated") {
stop-azVm -Name $SourceVmObject.Name -ResourceGroupName $SourceVmObject.ResourceGroupName -Force
Start-Sleep -Seconds 30
}
Let’s define the VM new name
$vmNewName = "dsc-lab-dns01"
One thing I love with the Azure PowerShell module is you can create a VM object and later, use this object to create a VM.
$NewVmObject = New-AzVMConfig -VMName $vmNewName -VMSize $SourceVmObject.HardwareProfile.VmSize
We can now create VM components.
$subnetID = (Get-AzNetworkInterface -ResourceId $SourceVmObject.NetworkProfile.NetworkInterfaces[0].id).IpConfigurations.Subnet.id
$nic = New-AzNetworkInterface -Name "$($vmNewName.ToLower())-0-nic" -ResourceGroupName $SourceVmObject.ResourceGroupName -Location $SourceVmObject.Location -SubnetId $SubnetId
Add-AzVMNetworkInterface -VM $NewVmObject -Id $nic.Id
Now we have to deal with disks. In the VM Object perspective there two types of disks, OS and data disk. Information about disks is located in the StorageProfile property.
To copy the VM, we need to create a snapshot for each disk and use snapshots to create new disks.
Let’s start with the OS disk.
$SourceOsDiskSku = (get-azdisk -ResourceGroupName $SourceVmObject.ResourceGroupName -DiskName $SourceVmObject.StorageProfile.OsDisk.name).Sku.Name
$SourceOsDiskSnapConfig = New-AzSnapshotConfig -SourceUri $SourceVmObject.StorageProfile.OsDisk.ManagedDisk.Id -Location $SourceVmObject.Location -CreateOption copy
$SourceOsDiskSnap = New-AzSnapshot -Snapshot $SourceOsDiskSnapConfig -SnapshotName "$($SourceVmObject.Name)-os-snap" -ResourceGroupName $SourceVmObject.ResourceGroupName
$TargetOsDiskConfig = New-AzDiskConfig -AccountType $SourceOsDiskSku -Location $SourceVmObject.Location -CreateOption Copy -SourceResourceId $SourceOsDiskSnap.Id
$TargetOsDisk = New-AzDisk -Disk $TargetOsDiskConfig -ResourceGroupName $SourceVmObject.ResourceGroupName -DiskName "$($vmNewName.ToLower())-os-vhd"
Set-AzVMOSDisk -VM $NewVmObject -ManagedDiskId $TargetOsDisk.Id -CreateOption Attach -Windows
We can now copy data disks. An Azure VM can have 0 to multiple data disk (it depends on de VM Size).
For that, we need to parse the DataDisks List. We need to take care of the Lun number so we will not run into problems after the restart
Foreach ($SourceDataDisk in $SourceVmObject.StorageProfile.DataDisks) {
$SourceDataDiskSku = (get-azdisk -ResourceGroupName $SourceVmObject.ResourceGroupName -DiskName $SourceDataDisk.name).Sku.Name
$SourceDataDiskSnapConfig = New-AzSnapshotConfig -SourceUri $SourceDataDisk.ManagedDisk.Id -Location $SourceVmObject.Location -CreateOption copy
$SourceDataDiskSnap = New-AzSnapshot -Snapshot $SourceDataDiskSnapConfig -SnapshotName "$($SourceVmObject.Name)-$($SourceDataDisk.name)-snap" -ResourceGroupName $SourceVmObject.ResourceGroupName
$TargetDataDiskConfig = New-AzDiskConfig -AccountType $SourceDataDiskSku -Location $SourceVmObject.Location -CreateOption Copy -SourceResourceId $SourceDataDiskSnap.Id
$TargetDataDisk = New-AzDisk -Disk $TargetDataDiskConfig -ResourceGroupName $SourceVmObject.ResourceGroupName -DiskName "$($vmNewName.ToLower())-$($SourceDataDisk.lun)-vhd"
Add-AzVMDataDisk -VM $NewVmObject -Name "$($vmNewName.ToLower())-$($SourceDataDisk.lun)-vhd" -ManagedDiskId $TargetDataDisk.Id -Lun $SourceDataDisk.lun -CreateOption "Attach"
}
Now that we have completed the VM configuration, we can create the VM.
New-AzVM -VM $NewVmObject -ResourceGroupName $SourceVmObject.ResourceGroupName -Location $SourceVmObject.Location
This is one of the methods to rename a VM. You can use it also to reconnect a VM from one virtual network to another.
About the Author:
Microsoft Azure MVP, Passionate about Cloud and DevOps. Co-organizers of the French PowerShell & DevOps UG . Find me on https://github.com/omiossec
Reference:
Miossec, O. (2020). Using PowerShell to rename, move or reconnect an Azure VM. Available at: https://dev.to/omiossec/using-powershell-to-rename-move-or-reconnect-an-azure-vm-i00 [Accessed: 2nd November 2020].