Cloning Windows Virtual Machine in Azure without having to stop it
Image from Pexels

Cloning Windows Virtual Machine in Azure without having to stop it

Zero downtime cloning of Virtual Machine in Azure using PowerShell

Creating a copy of an existing Virtual Machine on Azure is not really that much straight forward as you might think. The proper way as described in the documentation is to "generalize" Virtual Machine which puts it into a state where it can be used as a template for creating new Virtual Machines.

Unfortunately this way of creating a clone of VM on Azure makes the source VM inaccessible. This can be a big problem especially if you wan to clone an existing VM for the purpose of scaling them behind the load balancer or you just want to make an availability set to avoid any downtime during deployment.

You can always make a Snapshot of OS disk of the running VM and then create a boot-able Managed Disk, but unfortunately, Azure UI still does not support creating a VM and attaching and existing Managed Disk as a bootable one. Luckily all these options are available from the Cloud Shell directly from the Azure portal as an in-browser terminal.

Azure Cloudshell 

Azure Cloud Shell supports both bash and PowerShell, so you can use the one you prefer. For this case I will stick to PowerShell.

The idea behind this approach of cloning an existing VM is to:

  • Create a Snapshot of OS Managed disk of an existing VM
  • Create instance of Managed Disk from previously created Snapshot
  • Allocate static IP and Network Adapter instances for the new VM
  • Configure new VM by attaching Managed Disk, static IP and Network Adapter resources to the VM configuration instance
  • Create the VM using the configuration
  • Delete the Snapshot of the disk

These are the exact steps we are going to follow in the PowerShell script we are going to use to clone the existing VM instance.

Note

Since we are technically cloning only the disk of the existing VM, other elements of the VM (Static IP, Network Adapter, Virtual Machine Size, Geo Location...) are something we will create in the fly and are not exactly clones of the elements of existing VM, but once started you will have a clone of the Operating System running on the source VM you cloned from

In order to create resources for the new VM, you will need few values which you can find in the properties of the existing VM from Azure UI, but they might be a bit different than the ones you use in the script. Simple reason is that values shown in Azure UI are display names of these elements, while the actual name has a bit different value. You can search Azure documentation for this, but you can always use PowerShell to pull out these values.

Two main values you are going to need for creating a new VM are Azure data center geo Location where VM will be created and Size of a new VM

Azure geo location values

Microsoft keeps adding new data centers and therefore new locations keep getting onto the data center locations list. You might want to create a cloned VM in a different region to achieve geo redundancy and lower down the latency.

Here is how to get the list of data center geo locations currently available in Azure using PowerShell in Azure Cloud Shell in-browser console

Get-AzureRmLocation |Format-Table
    

This will produce the output as the following 

Location           DisplayName          Providers
--------           -----------          ---------
eastasia           East Asia            {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
southeastasia      Southeast Asia       {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.AppConfiguration…}
centralus          Central US           {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.AppConfiguration…}
eastus             East US              {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.AppConfiguration…}
eastus2            East US 2            {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
westus             West US              {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.AppConfiguration…}
northcentralus     North Central US     {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
southcentralus     South Central US     {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
northeurope        North Europe         {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
westeurope         West Europe          {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.AppConfiguration…}
japanwest          Japan West           {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
japaneast          Japan East           {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
brazilsouth        Brazil South         {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
australiaeast      Australia East       {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.AppConfiguration…}
australiasoutheast Australia Southeast  {Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql, Microsoft.ContainerRegistry…}
southindia         South India          {microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql…}
centralindia       Central India        {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
westindia          West India           {microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql…}
canadacentral      Canada Central       {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
canadaeast         Canada East          {Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql, Microsoft.ContainerRegistry…}
uksouth            UK South             {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
ukwest             UK West              {Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql, Microsoft.ContainerRegistry…}
westcentralus      West Central US      {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.AppConfiguration…}
westus2            West US 2            {Microsoft.CognitiveServices, microsoft.visualstudio, Microsoft.ServiceBus, Microsoft.Storage…}
koreacentral       Korea Central        {Microsoft.CognitiveServices, Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql…}
koreasouth         Korea South          {Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql, Microsoft.Web…}
francecentral      France Central       {Microsoft.CognitiveServices, Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql…}
francesouth        France South         {Microsoft.ClassicInfrastructureMigrate, Microsoft.DeploymentManager, Microsoft.DevTestLab, Microsoft.Kusto…
australiacentral   Australia Central    {Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql, Microsoft.Web…}
australiacentral2  Australia Central 2  {Microsoft.ServiceBus, Microsoft.Sql, microsoft.insights, Microsoft.ClassicInfrastructureMigrate…}
uaecentral         UAE Central          {Microsoft.Security, Microsoft.SqlVirtualMachine, Sendgrid.Email}
uaenorth           UAE North            {Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql, Microsoft.ContainerRegistry…}
southafricanorth   South Africa North   {Microsoft.CognitiveServices, Microsoft.ServiceBus, Microsoft.Storage, Microsoft.Sql…}
southafricawest    South Africa West    {Microsoft.Databricks, Microsoft.DBforMariaDB, Microsoft.DBforMySQL, Microsoft.DBforPostgreSQL…}
germanynorth       Germany North        {Microsoft.ServiceBus}
germanywestcentral Germany West Central {Microsoft.ServiceBus, microsoft.insights, Microsoft.EventHub, Microsoft.ManagedIdentity}

Azure VM size values

Another value you will need for the new VM is the Size. Virtual Machine sizes are basically short names for the predefined configurations. Each size name is associated with the configuration parameters which involve number of VCPUs and RAM size among others.

VM size directly affects the computing price, so it is important to pick the size that will work for you performance wise and at the same time cost effective. For Windows VMs, you can find list of VM Sizes on page Sizes for Windows virtual machines in Azure or just run the PoweShell command in Azure Cloud Shell console.

Get-AzureRmVmSize -location "eastus2"
    

You notice that Location parameter is required in order to list the VM sizes. This is because not all VM sizes are available in all regions, so when creating you new VM, once you pick the location, you need to use the VM size available in that location.

The output of the VM sizes fetch PowerShell script looks as following.

Name                   NumberOfCores MemoryInMB MaxDataDiskCount OSDiskSizeInMB ResourceDiskSizeInMB
----                   ------------- ---------- ---------------- -------------- --------------------
Standard_A0                        1        768                1        1047552                20480
Standard_A1                        1       1792                2        1047552                71680
Standard_A2                        2       3584                4        1047552               138240
Standard_A3                        4       7168                8        1047552               291840
Standard_A5                        2      14336                4        1047552               138240
Standard_A4                        8      14336               16        1047552               619520
Standard_A6                        4      28672                8        1047552               291840
Standard_A7                        8      57344               16        1047552               619520
Basic_A0                           1        768                1        1047552                20480
Basic_A1                           1       1792                2        1047552                40960
Basic_A2                           2       3584                4        1047552                61440
Basic_A3                           4       7168                8        1047552               122880
Basic_A4                           8      14336               16        1047552               245760
Standard_D1_v2                     1       3584                4        1047552                51200
Standard_D2_v2                     2       7168                8        1047552               102400
Standard_D3_v2                     4      14336               16        1047552               204800
Standard_D4_v2                     8      28672               32        1047552               409600
Standard_D5_v2                    16      57344               64        1047552               819200
Standard_D11_v2                    2      14336                8        1047552               102400
Standard_D12_v2                    4      28672               16        1047552               204800
Standard_D13_v2                    8      57344               32        1047552               409600

VM sizes availability across location is changing over time, so make sure you get the proper VM size name with the PowerShell command from above to avoid VM clone script failure. This is especially important for promo VM sizes which are not available at all time.

Note

Microsoft keeps updating Azure and some of the output values for regions and VM sizes might change or be expanded over time. To make sure you have the correct value for the PowerShell script to run, make sure you run the value fetching script in Azure Cloud Shell to have the latest values

Azure VM clone PowerShell script

As I mentioned above, we are going to follow few basic steps to achieve new VM that boots up the same copy of the OS from the point of time when the OS disk Snapshot was made. This approach will allow us to maintain 100% uptime of the source VM without having to "generalize" it.

Here is the actual script that will perform the VM clone. 

#Existing virtual network where new virtual machine will be created
$virtualNetworkName = '<Virtual Network Name>'

#Resource group of the VM to be clonned from 
$resourceGroupName = '<Resource Group Name>'

#Region where managed disk will be created
$location = '<Geo Location>'

#Names of source and target (new) VMs
$sourceVirtualMachineName = '<Source VM Name>'
$targetVirtualMachineName = '<Target VM Name>'

#Name of snapshot which will be created from the Managed Disk
$snapshotName = $sourceVirtualMachineName + '_OsDisk-snapshot'

#Name of the new Managed Disk
$diskName = $targetVirtualMachineName + '_OsDisk'

#Size of new Managed Disk in GB
$diskSize = 128

#Storage type for the new Managed Disk (Standard_LRS / Premium_LRS / StandardSSD_LRS)
$storageType = '<Storage Type>'

#Size of the Virtual Machine (https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes)
$targetVirtualMachineSize = '<Target VM Size>'

#Set the subscription for the current session where the commands wil execute
Select-AzureRmSubscription -SubscriptionId '<Subscription Id>'

#Get the existing VM from which to clone from
$sourceVirtualMachine = Get-AzVM -ResourceGroupName $resourceGroupName -Name $sourceVirtualMachineName

#Create new VM Disk Snapshot
$snapshot = New-AzSnapshotConfig -SourceUri $sourceVirtualMachine.StorageProfile.OsDisk.ManagedDisk.Id -Location $location -CreateOption copy
$snapshot = New-AzSnapshot -Snapshot $snapshot -SnapshotName $snapshotName -ResourceGroupName $resourceGroupName 

#Create a new Managed Disk from the Snapshot
$disk = New-AzureRmDiskConfig -AccountType $storageType -DiskSizeGB $diskSize -Location $location -CreateOption Copy -SourceResourceId $snapshot.Id
$disk = New-AzureRmDisk -Disk $disk -ResourceGroupName $resourceGroupName -DiskName $diskName

#Initialize virtual machine configuration
$targetVirtualMachine = New-AzureRmVMConfig -VMName $targetVirtualMachineName -VMSize $targetVirtualMachineSize

#Attach Managed Disk to target virtual machine. OS type depends OS present in the disk (Windows/Linux)
$targetVirtualMachine = Set-AzureRmVMOSDisk -VM $targetVirtualMachine -ManagedDiskId $disk.Id -CreateOption Attach -Windows

#Create a public IP for the VM
$publicIp = New-AzureRmPublicIpAddress -Name ($targetVirtualMachineName.ToLower() + '_ip') -ResourceGroupName $resourceGroupName -Location $location -AllocationMethod Dynamic

#Get Virtual Network information
$vnet = Get-AzureRmVirtualNetwork -Name $virtualNetworkName -ResourceGroupName $resourceGroupName

# Create Network Interface for the VM
$nic = New-AzureRmNetworkInterface -Name ($targetVirtualMachineName.ToLower() + '_nic') -ResourceGroupName $resourceGroupName -Location $location -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $publicIp.Id
$targetVirtualMachine = Add-AzureRmVMNetworkInterface -VM $targetVirtualMachine -Id $nic.Id

#Create the virtual machine with Managed Disk attached
New-AzureRmVM -VM $targetVirtualMachine -ResourceGroupName $resourceGroupName -Location $location

#Remove the snapshot
Remove-AzureRmSnapshot -ResourceGroupName $resourceGroupName -SnapshotName $snapshotName -Force

    
    

You can safely copy the whole script and paste it into Azure Cloud Shell console. The lines will be executed one by one and in the end you will get a new VM instance which runs a copy of the OS state from the source VM.

Alternatively, you can upload the script file from the Cloud Shell toolbar and execute it

Run Script File 

Note

Executing the script may take some time as it is initiating the resource provisioning in Azure. Creating of a VM especially take most of the time of script run.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

.NET

read more

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

Comments for this article