Delete Azure VMs & Clean Up with PowerShell

Published:1 July 2019 - 5 min. read

One of the most common uses of the Microsoft Azure cloud for administrators is virtual machines (VMs). It’s easy to create Azure VMs, but it’s not quite as intuitive to remove one. If you need to learn how to delete an Azure VM, you’ve come to the right place.

Not a reader? Watch this related video tutorial!
Not seeing the video? Make sure your ad blocker is disabled.

Sure, you can go to the Azure Portal, and find and delete an Azure VM easily enough. You could also use the Remove-AzVM PowerShell command in the Azure PowerShell module to quickly remove a VM but there’s a lot more to that VM than just the VM itself.

When that VM is created, you could have potentially created many other resources along with it that should be cleaned up as well. Resources like the below can all be associated with a VM that needs to be removed.

  • Boot diagnostics storage containers
  • Network interfaces
  • Public IP addresses
  • OS disk and status storage blobs
  • Data disks

In this article, we’ll cover how to build a PowerShell function called Remove-AzrVirtualMachine that will not only delete an Azure VM but also anything directly associated with it.

Delete Azure VM script
Delete Azure VM script

Prerequisites

To delete an Azure VM and cleanup other related resources with PowerShell, you’re going to need a couple of things.

  • The Azure PowerShell Module – This PowerShell module can be downloaded and installed via the PowerShell Gallery by running Install-Module Az.
  • Authenticated to an Azure subscription – You’ll need to be authenticated to the Azure subscription your VM is located in. To do this, run Connect-AzAccount.

To verify, you can then run Get-AzVm -Name <VMName> -ResourceGroupName <VMResourceGroupName> to check if it returns the VM. If no error is returned, you should be good to go.

Getting the Azure VM Object

To make things easier in this script, to delete an Azure VM, we’ll first get the VM object that contains all of the necessary information we’re looking for. To do that, we use the Get-AzVm command. For this article, I’ll be working with a VM called WINSRV19 in the MyTestVMs resource group.

$vm = Get-AzVm -Name WINSRV19 -ResourceGroupName MyTestVMs

You should now have the VM object stored in the $vm variable allowing you to read various objects from the variable as you progress through the script.

Removing the Boot Diagnostics Storage Container

When creating an Azure VM, you always have the option of creating a boot diagnostics container. This is useful for troubleshooting VM boot issues but doesn’t get removed when a VM is deleted. Let’s remedy that.

To remove the boot diagnostics container, you first need to figure out the name of the storage account the container resides. To find this storage account, you’ll have to do some parsing of the storageUri property that’s buried in the DiagnosticsProfile object on the VM.

To save you some time, here’s some regex to parse out that name.

$diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\\.').groups[1].value

Next, you’ll need to find the name of the boot diagnostics storage container. To find that, you’ll first need to find the VM ID using the Get-AzResource command. Here is some PowerShell to get that done for you.

if ($vm.Name.Length -gt 9) {
    $i = 9
} else {
    $i = $vm.Name.Length - 1
}

$azResourceParams = @{
    'ResourceName' = WINSRV
    'ResourceType' = 'Microsoft.Compute/virtualMachines'
    'ResourceGroupName' = MyTestVMs
}

$vmResource = Get-AzResource @azResourceParams
$vmId = $vmResource.Properties.VmId
$diagContainerName = ('bootdiagnostics-{0}-{1}' -f $vm.Name.ToLower().Substring(0, $i), $vmId)

Next, you’ll need the name of the resource group the boot diagnostics container is a part of.

$diagSaRg = (Get-AzStorageAccount | where { $_.StorageAccountName -eq $diagSa }).ResourceGroupName

Finally, you can now remove the storage container with the Remove-AzStorageContainer command.

$saParams = @{
    'ResourceGroupName' = $diagSaRg
    'Name' = $diagSa
}

Get-AzStorageAccount @saParams | Get-AzStorageContainer | where { $_.Name-eq $diagContainerName } | Remove-AzStorageContainer -Force

One resource down! Let’s keep going and continue on how to delete an Azure virtual machine from disk.

Finally Delete an Azure VM

Next, we’ll delete an Azure VM itself. Since you’ve already captured the VM in the $vm variable, you can pass that object to the Remove-AzVm command and be done with it.

$null = $vm | Remove-AzVM -Force

Removing Network Interfaces and Public IP Addresses

Next up, are one or more network interfaces (NICs) that were once attached to that VM. Using the NetworkInterfaces property on the VM object, we can loop through each ID, remove the NIC with the Remove-AzNetworkInterface command.

While we’re in this loop, we can also check the IpConfiguration property on each NIC to discover if that NIC has a public IP address associated with it. If so, we can remove that with the Remove-AzPublicIpAddress command.

Below you can see, I’m looking for all NICs, removing each one, checking for public IPs on each NIC and if found, parsing the PublicIpAddress property’s ID to get the name of the public IP address resource and remove it.

foreach($nicUri in $vm.NetworkProfile.NetworkInterfaces.Id) {
    $nic = Get-AzNetworkInterface -ResourceGroupName $vm.ResourceGroupName -Name $nicUri.Split('/')[-1]
    Remove-AzNetworkInterface -Name $nic.Name -ResourceGroupName $vm.ResourceGroupName -Force

    foreach($ipConfig in $nic.IpConfigurations) {
        if($ipConfig.PublicIpAddress -ne $null) {
            Remove-AzPublicIpAddress -ResourceGroupName $vm.ResourceGroupName -Name $ipConfig.PublicIpAddress.Id.Split('/')[-1] -Force
        }
    }
}

Removing the OS Disk

To delete an Azure VM, the OS disk isn’t removed. The OS disk is a storage blob you can remove with the Remove-AzStorageBlob command but first, like the other steps, you’ll have to do some searching to find the correct parameter values to pass to it.

In the below example PowerShell code snippet, I’m first finding the name of the OS disk storage container. Once I find that I’m then using that along with the storage account the OS disk storage container resides on to pass to Remove-AzStorageBlob to get the OS disk removed.

$osDiskUri = $vm.StorageProfile.OSDisk.Vhd.Uri
$osDiskContainerName = $osDiskUri.Split('/')[-2]
$osDiskStorageAcct = Get-AzStorageAccount | where { $_.StorageAccountName -eq $osDiskUri.Split('/')[2].Split('.')[0] }
$osDiskStorageAcct | Remove-AzStorageBlob -Container $osDiskContainerName -Blob $osDiskUri.Split('/')[-1]

Removing the OS Disk Status Blob

To clean up the OS disk status blog, I need to find the storage container the OS disk is in, assume the blog itself ends in status, and then pass that to Remove-AzStorageBlob to obliterate that blob.

$osDiskStorageAcct | Get-AzStorageBlob -Container $osDiskContainerName -Blob "$($vm.Name)*.status" | Remove-AzStorageBlob

Removing Attached Data Disks

Finally, some VMs may have data disks attached to them that you’d rather not use elsewhere. Not a problem. To delete an Azure VM properly, we can remove those too! This is the final step in deleting an Azure VM and all of its components.

First, you’ll read the Uri property embedded deep in the StorageProfile object on the original VM object you retrieved. Since there can be more than one data disk with a URI, you’ll loop over each of these URIs to find the storage account each one is on.

Once you’ve discovered the storage account of each one, you’ll use that and parse the storage URI to form the blob name to pass to the Remove-AzStorageBlob command, as shown below.

if ($vm.DataDiskNames.Count -gt 0) {
    foreach ($uri in $vm.StorageProfile.DataDisks.Vhd.Uri) {
        $dataDiskStorageAcct = Get-AzStorageAccount -Name $uri.Split('/')[2].Split('.')[0]
        $dataDiskStorageAcct | Remove-AzStorageBlob -Container $uri.Split('/')[-2] -Blob $uri.Split('/')[-1]
    }
}

Summary

We’ve covered quite a bit in this article. Following best PowerShell coding practices, you could quickly build a tool from this code. Lucky for you, I’ve already done it for you! If you’d like to see an example of how this code could be implemented to delete an Azure VM, check out the Remove-AzrVirtualMachine function.

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!