Parallel Delete Virtual Machines in Azure:

This script will delete an Azure Resource manager Virtual Machine.

- It will also delete the associated Network Interface Card (NIC).

- optionally delete the public ip address.

- It will also remove both STANDARD and MANAGED Disks.

   - Including both the OSDisk and the DATADisks.


This function assumes a few things in relation to the storage of the STANDARD disks, which is that they all use the SAME storage account. 

If your DATA Disks use different storage accounts than your OSDisks, then you need to update the function accordingly.


You also need to make sure you  first log in and then SAVE YOUR CONTEXT


OR you can even use:


then login


plus ensure you have the correct subscription selected


select-azsubscription -id {guid}

Then you don't need to save your context plus you can update this line

Try {
                $ctx = Import-AzureRmContext -path $home\ctx.json -ErrorAction Stop


Try {
                $ctx = get-azcontext



- Added a delay in the loop to stop locks on TokenCache.dat

- fixed issue with Disk names


#run these steps 
# 1 login to azure 
# 2 save your context 
Save-AzureRmContext -Path $home\ctx.json -Force 
# 3 define The resource group where the servers are deployed  
$rg = 'AZEUS2-MY-APP'  
# 4 define the role (or server name) to Delete the SQL and the Integration services role servers  
$role = 'SQL|IS'  
# 5 Run the following first to confirm which machines/s will be deleted.   
Get-AzureRMVM -ResourceGroup $rg | Where Name -Match $role 
# 6 execute the function. 
# choose to delete public ip? default is off. 
# (update param to default value $true to always delete public ip) 
Remove-AzureRMVMInstanceParallel -ResourceGroup $rg  -VMName $role  -Wait -RemovePublicIP $true

* Note there is no confirm prompt on this so be careful.

Here is another script used to Create a VM


Here is another script to delete VM's not in parallel


Here is another script to delete VM Extensions in parallel



Function Remove-AzureRMVMInstanceParallel { 
 Param ( 
    # The VM name to remove, regex are supported 
    # The Script will not wait for the background jobs by default, use this switch to wait 
    # A configuration setting to also delete public IP's, off by default 
    $RemovePublicIP = $False 
    # Remove the VM's and then remove the datadisks, osdisk, NICs 
$jobs = Get-AzureRmVM -ResourceGroupName $ResourceGroup | Where Name -Match $VMName  | foreach { 
        # avoid locks on the tokencache.dat file 
        Start-Sleep -Seconds 3 
        Start-Job -ScriptBlock { 
            Try { 
                $ctx = Import-AzureRmContext -path $home\ctx.json -ErrorAction Stop 
                $resourceGroup = $using:Resourcegroup 
                $VMName = $using:VM 
                $RemovePublicIP = $using:RemovePublicIP 
                # $ctx 
                # Get-AzureRmResourceGroup -Name $resourceGroup 
                Write-Verbose -Message "Connected to $($ctx.Subscription.Name)" -Verbose 
                Write-Verbose -Message "The following resources were found:" 
                $VM = Get-AzureRmVM -ResourceGroupName $resourceGroup -Name $VMName.Name -Verbose 
                $DataDisks = @($VM.StorageProfile.DataDisks.Name) 
                $OSDisk = @($VM.StorageProfile.OSDisk.Name) 
                $NICS = @($VM.NetworkProfile.NetworkInterfaces) 
                $ManagedDisk = $VM.StorageProfile.OsDisk.ManagedDisk 
                ($OSDisk + $DataDisks) 
                $NICS | Foreach ID 
                # Remove confirm preference for background jobs 
                #if ($pscmdlet.ShouldProcess("$($VM.Name)", "Removing VM, Disks and NIC: $($VM.Name)")) 
                    Write-Warning -Message "Deleting VM:[$($VMName.Name)] from RG:[$resourceGroup]" 
                    #DELETE Virtual Machine 
                    $VM | Remove-AzureRmVM -Force -Confirm:$false 
                    #DELETE NIC 
                    $NICS | where {$_.ID} | ForEach-Object { 
                        $NICName=split-path $_.ID -leaf 
                        Write-Warning -Message "Removing NIC: $NICName" 
                        $Nic = Get-AzureRmNetworkInterface -ResourceGroupName $ResourceGroup -Name $NICName 
                        $Nic | Remove-AzureRmNetworkInterface -Force  
                        # Optionally remove public ip's, will not save the static ip, if you need the same one, do not delete it. 
                        if ($RemovePublicIP) 
                            $nic.IpConfigurations.PublicIpAddress | where {$_.ID} | ForEach-Object { 
                                $PublicIPName = Split-Path -Path $_.ID -leaf 
                                Write-Warning -Message "Removing PublicIP: $PublicIPName" 
                                $PublicIP = Get-AzureRmPublicIpAddress -ResourceGroupName $ResourceGroup -Name $PublicIPName 
                                $PublicIP | Remove-AzureRmPublicIpAddress -Force 
                    if($ManagedDisk) { 
                        #DELETE MANAGEDDISKS 
                       ($OSDisk + $DataDisks| where {$_| ForEach-Object { 
                            Write-Warning -Message "Removing Disk: $_" 
                            Get-AzureRmDisk -ResourceGroupName $ResourceGroup -DiskName $_ | Remove-AzureRmDisk -Force 
                    else { 
                        #DELETE DATA DISKS  
                        $saname = ($VM.StorageProfile.OsDisk.Vhd.Uri -split '\.' | Select -First 1) -split '//' |  Select -Last 1 
                        $SA = Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $saname 
                        $VM.StorageProfile.DataDisks | foreach { 
                            $disk = $_.Vhd.Uri | Split-Path -Leaf 
                            Get-AzureStorageContainer -Name vhds -Context $Sa.Context | 
                            Get-AzureStorageBlob -Blob  $disk | 
                        #DELETE OS DISKS 
                        $saname = ($VM.StorageProfile.OsDisk.Vhd.Uri -split '\.' | Select -First 1) -split '//' |  Select -Last 1 
                        $disk = $VM.StorageProfile.OsDisk.Vhd.Uri | Split-Path -Leaf 
                        $SA = Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $saname 
                        Get-AzureStorageContainer -Name vhds -Context $Sa.Context | 
                        Get-AzureStorageBlob -Blob  $disk | 
                    # If you are on the network you can cleanup the Computer Account in AD             
                    # Get-ADComputer -Identity $a.OSProfile.ComputerName | Remove-ADObject -Recursive -confirm:$false 
                # remove confirm preference for background jobs 
            Catch { 
                Write-Warning -Message 'You must save your Context first [Save-AzureRmContext -Path $home\ctx.json -Force]' 
                Write-Warning $_ 
sleep -Seconds 30 
$jobs | Receive-Job -Keep 
if ($Wait) 
    sleep -Seconds 30 
    $jobs | Wait-Job | Receive-Job 
    Write-Warning "Run the following to view status of parallel delete`nGet-Job | Receive-Job -Keep"