Monday, October 7, 2013

Exporting the VHD of a running VM with Hyper-V 2012

A co-worker recently asked me about how to clone / export a running VM on Hyper-V 2012.

My first reply was; “upgrade to Hyper-V 2012 R2 and it is built-in”. 

Unfortunately that didn’t meet his needs, he is stuck in the Hyper-V 2012 world for a bit.

I came up with a process, it is not a pretty process, that is within all the parameters of file locking, doing things the way that you ‘should’, etc.

The key thing to wanting to ‘clone’ or export a VM is that you really want the virtual disk.  That is the ‘state’ of the machine.  The settings are easily copied and relatively incidental, the most important part is the virtual disk. 

I say that because this entire convoluted process is all about getting a very clean virtual disk state.  In this entire process, the settings of the machine (CPU, RAM, dynamic memory, virtual switch attachment, etc.) don’t matter.  And in the real world (outside of my little perfect test world) they really don’t matter until you Import.

Enough rambling on.  So, what is this process anyway?  In a nutshell it is:

If you take a snapshot of a VM, you can then add a differencing disk to the parent disk of the snapshot, create a VM from that, export that VM, then destroy the VM, then destroy the differencing disk.

Because this is not a snapshot, with the export Hyper-V gives you the differencing disk plus the parent.
If you exported a snapshot you get a single virtual disk, since Hyper-V does special things with AVHDX files.
If you want a single file, then you merge the diff that is in the export.

I know that some of my blog readers dream in command line, so here comes the PowerShell.

Special note:  This is specific to Hyper-V 2012 and works because of live merging and the built-in PowerShell provider.  Hyper-V 2012 R2 does not need all this mess, just take a snapshot and Export.  Hyper-V 2008 or 2008 R2 does not have a built-in PowerShell provider, but you could do all this with WMI.

$vm = get-vm "datest"

# I always want 'now' so we take our own snapshot
$checkPoint = Checkpoint-VM -VM $vm -SnapshotName "clone" -Passthru

# Create a differencing disk and link it to the disk of the snapshot.
$diffVhd = New-VHD -Differencing -ParentPath $checkPoint.HardDrives[0].Path -Path ("D:\Test\" + $checkPoint.Name + ".vhdx")

# If you really care about the exact configuration of your VM and want to Import it on the other side, then do the configuration only export using WMI:  http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/03/24/performing-a-configuration-only-export-import-on-hyper-v.aspx
# on the Import side you would 'fix-up' the configuration and use the merged new disk from later on in this example.  http://itproctology.blogspot.com/2012/08/handling-import-vm-errors-in-server.html

$clone = New-VM -Name $checkPoint.Name -VHDPath $diffVhd.Path

Export-vm -VM $clone -Path D:\Test -Passthru

Remove-VM -VM $clone -Force
Remove-Item $diffVhd.Path

$vhds = Get-ChildItem -Path D:\test -Recurse -File -Include "*.vhd*" | Get-VHD

foreach ($vhd in $vhds) {
    if ($vhd.VhdType -eq "Differencing") {
        $parent = Get-Item $vhd.ParentPath

        Merge-VHD $vhd.Path -Force
    }
}

I am going to mention it again.  I am using the Export process to get a clean virtual disk, not to have a proper VM configuration.

Use Ben’s Configuration Only export to get the configuration XML.  Then on Import use the Fix-up methodology to point to the new VHD.

Sounds like I need a second blog to put this all together.

No comments: