Clone VM on Win 2012 Hyper-V v3 when it is running using Powershell
I wanted to create a function that could help an IT Pro Admin with the task to create a clone of a running VM, Yes you can use the Export-VM cmdlet but then your VM must be turned off and in some cases, for example when you want to test a new release or patch on a production system but first test it in a safe environment and you are not allowed to stop the original VM.
The function exists in System Center Virtual Machine Manager but there it also must be turned off
So how do I do? I have made a PowerShell function that take a snapshot, copies the vhd files and creates a new VM, connect the vhd´s and network cards, configures the VM with number of processors, dynamic memory etc.
As the Snapshot merges the vhdx files when the VM is running in this new Hyper-V version I thought it was an sufficient way to solve that the VM actually was not writing to the .vhdx files when I copy them but into the .avhdx diff file.
This is a version 0.1 and yes it need some development but right now I do not have the time to make it supernice,
Here you can see it in action
And when It is finished It looks like this in the gui
And here is the PowerShell function
<# .Synopsis Function to clone a running VM .DESCRIPTION This function can be used to clone a running vm and connect the copied vhd´s and network .EXAMPLE Clone-VM -VMName vmdisktest -VMCloneName vmdisktest-clone -Path c:\VMs .EXAMPLE Clone-VM -VMName vmdisktest -VMCloneName vmdisktest-clone -Path c:\VMs -Switch Private .Notes Author: Niklas Akerlund Date: 2012-06-19 #> function Clone-VM { [CmdletBinding()] [OutputType([int])] Param ( # Name of the VM to be cloned [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] $VMName, [string] $VMCloneName, # Where to store the VM-clone [string] $Path, # Set to another network switch [string] $Switch = " " ) # Get VM $VM = Get-VM $VMName $VHDs = Get-VMHardDiskDrive -VM $VM #$VHDPath = (Get-VMHardDiskDrive -VM $VM).Path $VHDClonePath = "$Path\$VMCloneName\Virtual Hard Disks\" # Create a new array of VHD info $VHDOrg = @() foreach ($VHD in $VHDs){ $data = New-Object PSObject -property @{ VHDName = (Get-Item $VHD.Path).Name VHDPath = $VHD.Path ControllerType = $VHD.ControllerType ControllerNumber = $VHD.ControllerNumber ControllerLocation = $VHD.ControllerLocation } $VHDOrg +=$data } $VMNics = Get-VMNetworkAdapter -VM $VM # Take snapshot $VM | Checkpoint-VM New-Item -ItemType directory -Path $VHDClonePath New-VM -Name $VMCloneName -Path $Path -NoVHD -MemoryStartupBytes $VM.MemoryStartup -BootDevice IDE $VMClone = Get-VM -Name $VMCloneName Get-VMNetworkAdapter -VMName $VMCloneName | Remove-VMNetworkAdapter # Configure VM-Clon if ($VM.DynamicMemoryEnabled){ Set-VM -VMName $VMCloneName -ProcessorCount $VM.ProcessorCount -DynamicMemory -MemoryMinimumBytes $VM.MemoryMinimum -MemoryMaximumBytes $VM.MemoryMaximum }else{ Set-VM -VMName $VMCloneName -ProcessorCount $VM.ProcessorCount -StaticMemory } # Add all network cards foreach ($VMNic in $VMNics){ if ($Switch -eq " "){ Add-VMNetworkAdapter -VMName $VMCloneName -SwitchName $VMNic.SwitchName -IsLegacy $VMNic.IsLegacy }else{ Add-VMNetworkAdapter -VMName $VMCloneName -SwitchName $Switch -IsLegacy $VMNic.IsLegacy } } # Copy all VHDs foreach ($VHDcopy in $VHDOrg){ $Dest = $VHDClonePath + $VHDcopy.VHDName Copy-Item -Path $VHDcopy.VHDPath -Destination $Dest Add-VMHardDiskDrive -VMName $VMCloneName -ControllerType $VHDCopy.ControllerType -ControllerLocation $VHDCopy.ControllerLocation -ControllerNumber $VHDCopy.ControllerNumber -Path $Dest } # Remove snapshot $VM | Remove-VMSnapshot }
Good luck in testing, but do take in consideration that this is an copy of the running VM so do not start it at the same time on the same network or you will get IP collision etc, as you can see above I have added an -Switch parameter that you can use to set the network cards of the VM to be connected on another switch to avoid any problems.. 🙂
Comments
Great stuff, thanks for sharing! We’ll try and test the script when we get a chance and will post back any bugs or improvements we find, cheers!
you article doesn’t mention sysprep – don’t you sysprep your machines before cloning?
When I do a clone it is the exact copy of a running machine so no sysprep as you want it to be the same 🙂
Great job, thank you very much!
Hello Niklas,
very cool script , but if I clone a GEN2 VM the script creates a GEN1 VM 🙂 . Thanks for your support, regards Steffen
Nice script
Niklas,
After using your function with hyper-v on my desktop with version 5.0 powershell. Discovered the following requires lines fixed issues I had when using your script again.
#requires -version 3.0
#requires -module hyper-v
the Hyper-v module being the most important.