TLDR – If you are not interested in how the PowerShell script works and just want to jump straight to the solution see the PowerShell script below; just be aware that the script only works when moving a VM to another vNET in the same subscription. To move a VM to a vNET in another subscription you need to follow a different process which will be documented in a future blog post; let me know in the comments if you’d like to see this happen.

Moving an Azure VM to another vNET isn’t easy

You’d think that since VMs move around a lot on networks that moving an Azure VM from one vNET to another in would be a simple task… it is not. In fact, Microsoft’s official view on this approach is that they do not support it – so this means you are left to figure it out for yourself.

If you research the Internet, you will find various workarounds on how to achieve this, the part they all agree on is that you need to delete the VM and then recreate it. The problem I’ve discovered with these solutions is that nearly all of them require you to perform the steps manually from the Azure portal. In addition, these solutions don’t bring all VM settings across which leads to more issues down the track. In summary, I struggled to find a clean and simple solution to this problem, so I decided to work it out myself. The PowerShell script below automates the entire process from start to finish, and brings across every setting from the original VM, except the NIC. The NIC has to be removed as this is where the problem lies (explained below).

Why is it so hard?

The biggest sticking point when moving an Azure VM to another vNET is that the VM must have at least one NIC and it must be attached to a vNET always. In other words, once a VM’s NIC has been attached to a vNET (which you do when you create it) you can never detach it therefore binding it indefinitely to that vNET.

So, how do we get around it? Well at first glance you have two options:

  • Attach the VM’s NIC to the destination vNET whilst still being attached to the source vNET, then remove it from the source vNET. This won’t work as Azure does not allow a VM’s NIC to be attached to two different vNETs at the same time.
  • Add a second NIC, attach it to the new vNET then delete the old NIC. This won’t work either as Azure doesn’t allow this also.

The only way to get around this limitation is to backup the VM config, delete the VM, then re-create it with the saved config and attach it to new vNET on VM creation. Doing this is a lengthy process and the steps must be done in a specific order so I have documented them below with the script.

The PowerShell Script

The below script requires that you populate the variables first. I have added detailed comments for each line, please read them carefully before executing the script so you do not make any mistakes. I would also advise running it on a test machine first as the script has no error handling.

One caveat – Since you will be moving the VM to another vNET, the IP address will need to be changed. If you have assigned a static IP address to the VM you will need to update it before it moves. The easiest way to handle this is to set it to DHCP. This way, when it boots up on the new vNET it will have a valid IP configuration and you won’t run into any network problems. 

IMPORTANT: This PowerShell script only works when moving VMs to another vNET within the same subscription. Do not use this script to move VMs to another vNET to another subscription as it will fail; the reason for this and the workaround will be documented in a future blog post.

The PowerShell script does the following:

  • Logs into Azure, and asks you to select a subscription.
  • Takes a copy of the VM settings and saves it into a variable $original_VM.
  • The next steps amend the saved config not the live VM:
    • Detaches the VM’s existing NIC.
    • Creates a new NIC, attaches it to the destination vNET and attaches it to the VM.
    • Deletes some config settings which would cause the new VM deployment to fail otherwise (see script for details)
    • VM is now ready to be re-created.
  • Exports the original unmodified VM as an Azure ARM template – This step allows you to rebuild the VM in it’s original state if anything goes wrong.
  • Deletes the original VM. Note: the disks are not deleted, these are re-attached next.
  • Creates a new VM based on the modified settings above.
#This script should only be used to move VMs from vnet to vnet within the same subscription.
#It won't work when moving VMs between subscriptions.
 
#Note you need the AzureRM module installed. The next line will attempt to detect if it is not installed and install it for you.
#If for any reason it doesn't work you will need to DL the module manually.
#Check that AzureRM module is installed and if not then install it
$temp= (Get-Module -ListAvailable | ? {$_.name -eq 'azurerm'}) 
if ($temp.count -eq 0) {Install-Module azurerm}
 
#########Variables################################################
$original_VM_Name = 'type_VMNAME here'                                  #Enter here the VMname which you want to move
$Newnicname = $original_VM_Name +'NIC'                                  #The script must create a new nic which will get attached to the destination vNet, name the nic here our leave as is to be automatically named.
$original_VM_resource_group ='RG where VM resides'                      #Enter here the Resource Group name the VM is in
$Destination_vnet_name = 'enter destination vNET name'                  #Enter here the vnet you wish to move the VM to
$Destination_subnet_name= 'subnet name only'                            #Enter here the destination subnet name, This should be the subnet name only, not vNET_name/subnet
$Destination_vnet_resource_group = 'destination vnet RG'                #Enter here the RG name that destination vNet belongs to (this can sometimes be different to the VM RG)
$Region = "australiaeast"                                               #set the location of where to move the VM to
########End Varibles###############################################
 
 
 
#######################Login to Azure###############################
Write-Host "Log into Azure Services..."
#Azure Account Login
try {
                Login-AzureRmAccount -ErrorAction Stop
}
catch {
                # The exception lands in [Microsoft.Azure.Commands.Common.Authentication.AadAuthenticationCanceledException]
                Write-Host "User Cancelled The Authentication" -ForegroundColor Yellow
                exit
}
 
#Prompt to select an Azure subscription
Get-AzureRmSubscription | Out-GridView -OutputMode Single -Title "Select a subscription" | ForEach-Object {$selectedSubscriptionID = $PSItem.SubscriptionId}
 
# Set selected Azure subscription
Select-AzureRmSubscription -SubscriptionId $selectedSubscriptionID
 
 
 
#########################Start Script#############################
 
 
#Function that creates the new nic and attaches it to the VM
function NewNIC($nicname, $vnetname, $rg, $region) {
    $vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $rg -Name $vnetname
    $nic = New-AzureRmNetworkInterface -Name $nicname -ResourceGroupName $original_VM_resource_group -Location $region -Subnet ($vnet.Subnets | ? {$_.name -eq $Destination_subnet_name})
    Write-Output $nic.Id
}
 
#Get details on the VM to move
$vm = Get-AzureRmVM -Name $original_VM_Name -ResourceGroupName $original_VM_resource_group
 
#Remove old NIC
$newvm = $vm | Remove-AzureRmVMNetworkInterface
 
#Create new NIC and attach it to destination vNET then attach the new NIC to the VM 
$newvm = Add-AzureRmVMNetworkInterface -VM $newvm -Id (NewNic -nicname $Newnicname -vnetname $Destination_vnet_name -rg $Destination_vnet_resource_group -region $Region)
 
#Remove some info from original VM which conflicts when creating a new VM
$newvm.OSProfile = $null
$newvm.StorageProfile.ImageReference = $null
$newvm.StorageProfile.OsDisk.CreateOption ='attach'
 
#Save VM config and export to temp folder in case you need to roll back
Export-AzResourceGroup -ResourceGroupName $original_VM_resource_group -Resource $vm.Id -path "c:\temp\$original_VM_Name.json"
 
#Remove/delete the VM from Azure.
Write-Output "Removing VM. Disks don't get removed and are readded next"
$vm | Remove-AzureRmVM
 
#Deploy new VM to Azure
Write-Output "creating the new VM"
New-AzureRmVM -ResourceGroupName $original_VM_resource_group -Location $Region -VM $newvm -AsJob</pre>
Write-Output "Completed"
Print Friendly, PDF & Email