Consolidate several VMs to a single virtual network with this script

We recently went over the details and implications of moving a VM between virtual networks. There are some compelling reasons to have a single virtual network when your design and security requirements allow it. For starters, it improves the VM network performance between virtual machines, saves money where the virtual network peering may not be required (depending on the design), and allows the use of an accelerated network, which has significant performance improvements within the same virtual network. For my current customer, they decided to consolidate several VMs to a single virtual network. To save time during the process, I created a script to allow a smooth migration using the supported methods. The goal of this article is to give you the tools to perform the same process on your network. The script will gather all requirements and configuration that are required to be kept during the transition as you consolidate VMs. Feel free to adapt the script to your needs.

The code step-by-step

The script will receive three parameters. All of them will be the name of these resources: virtual machine name, virtual network, and virtual subnet. The names are the actual names of the resources, and for the virtual network and subnet, we are looking for the target/destination.

The first step is to validate if all of them are valid. We are going to use Get-AZvm to check if the virtual machine exists, if not then we are going to inform that to the users and exit the script. We are going to check if the virtual network exists, and if it does exist, then we have enough information to check the subnet. In the case of not finding either a virtual network or subnet, an error message is displayed, and the script is ended.

If the virtual machine is valid, we will create thee variables. The $tVM will store all the virtual machine information, such as name, resource group, location, and so forth. The $tDataDisks variable will get all information related to the Data Disks associated with the VM, including the order, sizes, type, and cache settings. The $tOSDisk will store information related to the operating system disk of the VM.

if (!(get-azvm -name $VMName)) {
        Write-Host
        Write-Host -ForegroundColor Yellow "[ERROR] VM was not found. Please check the VM name and make sure that you are in the right subscription."
        write-Host
        Break
        } Else {
            $tVM = Get-AzVM -Name $vmName
            $tDataDisks = (Get-AzVM -Name $vmName).StorageProfile.DataDisks
            $tOSDisk = (Get-AzVM -Name $vmName).StorageProfile.OSDisk
        }
    If (!(Get-AZVirtualNetwork -Name $VirtualNetwork)){
        Write-Host
        Write-Host -ForegroundColor Yellow "[ERROR] Virtual Network was not found. Please check the Virtual Network name and make sure that you are in the right subscription."
        write-Host
        Break
    } Else{
        $tvnet = Get-AZVirtualNetwork -Name $VirtualNetwork
        If (!(Get-AzVirtualNetworkSubnetConfig -Name $VirtualSubnet -VirtualNetwork $tvnet -ErrorAction SilentlyContinue)) {
            Write-Host
            Write-Host -ForegroundColor Yellow "[ERROR] Subnet was not found. Please check the Virtual Network name and make sure that you are in the right subscription."
            write-Host
            Break
        }
    }

Now that we have all the data checked, we will inform what the script will perform in a nutshell and ask confirmation from the user. We will be using read-host cmdlet and ask for a simple yes or no answer.

Write-Host -ForegroundColor Yellow "[Warning] This process is about to move the $VMName to the Virtual Network $Virtualnetwork."
Write-Host "Note #1: The VM will be deallocated, removed, and recreated with the same disks on the new virtual network."
Write-Host "Note #2: In case of any issues during the script, all VM configuration will be displayed, and can be used to recreate the VM manually."
Write-Host "Note #3: Between the VM deletion and VM creation, there is a delay of 2 minutes. Be patient."
$tAnswer = Read-Host -Prompt "Please, type [Yes] to confirm, or [no]"

The next step is to check the answer from the user, and if the answer is yes, we know that the end-user is aware of the changes, and we can go ahead and perform the required tasks. Before removing the VM, we will retrieve all the information required from the existing VM, and we will print that on the console. By doing that, we guarantee that if the script does not work during execution time, we can always recover the VM using the information from the original VM. All variables were gathered during the test of the VM, and we are going to print out the information that can help to build the VM from scratch in a worst-case scenario.

If ($tAnswer -eq ‘yes’){
# Printing the information for future use
Write-Host
Write-Host -ForegroundColor Green ‘Original VM Info. Use this info for validation or plan B in case of any error.’
$tVM.Name
$tVM.Location
$tVM.HardwareProfile.VmSize
$tVM.ResourceGroupName
Write-Host -ForegroundColor Green ‘Disk Information’
$tDataDisks
$tOSDisk

At this point, we gathered all the information and printed that out on the screen and into our variables. Our next step is to remove the VM, and we are going to wait 120 seconds before moving to the process to re-create the VM in the new virtual network.

#Removing the VM
Remove-AzVM -Name $tVM.Name -ResourceGroupName $tVM.ResourceGroupName -Force
Start-Sleep 120

We have validated all the information provided at the beginning of the script. We need to get a virtual network using Get-AZVirtualNetwork cmdlet to the $vnet variable. The same for the subnet using the Get-AZVirtualNetworkSubnetConfig cmdlet. In this one, we need to pass the virtual network object that we retrieved in the previous step.

We will use a variable called $VirtualMachine to create the initial configuration (New-AZVMConfig), add the operating system disk (Set-AZVMOSDisk), add a network interface (New-AZNetworkInterface and Add-AZNetworkInterface). Last but not least, we will add every single data disk using a ForEach using Add-AZVMDataDisk. The final step is to use the New-AZVM using all variables that we used so far to store the information for the new virtual machine.

In all cmdlets below, we use the actual information from the original VM that we stored in the variables before deleting it.

#Gathering information to create the new VM
$vnet = Get-AzVirtualNetwork -Name $VirtualNetwork
$vsubnet = Get-AzVirtualNetworkSubnetConfig -Name $VirtualSubnet -VirtualNetwork $vnet
$VirtualMachine = New-AzVMConfig -VMName $tVM.Name -VMSize $tvm.HardwareProfile.VmSize
$VirtualMachine = Set-AzVMOSDisk -VM $VirtualMachine -ManagedDiskId $tvm.StorageProfile.OsDisk.ManagedDisk.id -CreateOption Attach -Windows
$nic = New-AzNetworkInterface -Name ($VirtualMachine.Name.ToLower()+’_vnic’) -ResourceGroupName $tVM.ResourceGroupName -Location $tVM.Location -SubnetId $vsubnet.Id -Force
$VirtualMachine = Add-AzVMNetworkInterface -VM $VirtualMachine -Id $nic.Id
ForEach ($Disk in $tDataDisks){
$VirtualMachine = Add-AzVMDataDisk -VM $VirtualMachine -Name $Disk.Name -CreateOption Attach -Lun $Disk.Lun -ManagedDiskId $Disk.ManagedDisk.Id -Caching $Disk.Caching
New-AzVM -ResourceGroupName $tvm.ResourceGroupName -Location $tvm.Location -VM $VirtualMachine
} }

Consolidate VMs: Where to get the full script

In this article, we went over some of the steps required to consolidate several VMs by gathering information from any given VM, save the information in PowerShell variables, print them out on the console (as plan B), remove and provision a new VM with the same features as the original VM. The entire script can be found at my GitHub using this link here.

About The Author

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top