This is adapted from this post.
This is not an easy task, but thanks to DISM the end result VM should be more or less the same - keep this in mind if running it on production servers (though I’ve had no problems so far).
I recommend you check your OS supports UEFI - for Windows I’m pretty sure you’re safe on x64 Win 8.1/2012R2 and up.
To summarise what’s going to happen to the target VM:
Besides a couple of minor gotchas, none of the above is rocket science. However, what I’m going to entirely ignore are considerations such as:
The first thing I’m going to do is to disable the recovery environment on the source machine while it is running, by running the following command from an elevated command prompt (note DON’T do this on the parent partition, it’s inside the VM!):
reagentc /info
If the output indicates the Windows recovery environment (WinRE) is enabled, disable it.
reagentc /disable
The reasons for disabling it are due to tight coupling between BCD and the recovery environment configuration. It’s just much simpler to migrate the virtual machine when it is not configured. We will re-enable it once the virtual machine has been migrated.
Next, I’m going to cleanly shutdown the generation 1 virtual machine (I really hope you don’t need instructions for that…), and mount its VHDX in the host.
From an elevated PowerShell prompt where the VHDX resides, run:
Mount-VHD –ReadOnly .\migrateme.vhdx
At this point you could do some fancy PowerShell to find out what drive letter has popped up on your local machine as the Windows installation for the generation 1 virtual machine. In my case, I just used Explorer and can see it’s drive H:. The system partition was also given a drive letter, G:. If no drive letters are present, it could be policy on the parent partition, but you can use diskpart or diskmgmt.msc to assign letters and/or online the disk.
We’re going to use dism to capture the image. Note that you can use regular inbox dism for this, it doesn’t need to be the version of dism from the ADK which I used in a previous part of this series. From an elevated prompt, run the following replacing H: with the appropriate drive letter for the Windows Installation.
DISM /Capture-Image /ImageFile:captured.wim /Name:"IPutTheVMNameHere" /CaptureDir="H:\"
The next job is to create a new VHDX which we will partition in a format suitable for use by a generation 2 virtual machine (note that MBR is required for generation 1, GPT is strongly recommended for generation 2). I am going to use GPT, as should you.
This gets a little tricky for sizing purposes, especially when your source disk is almost full. From the disk partition layout above, the source VHDX is 127GB, and during operating system installation, Windows created a 350MB System Reserved partition.
In a typical GPT layout, you’d have a (minimum) 100MB ESP FAT32, a 16MB Microsoft reserved partition (hidden from Disk Management), and the remainder for the system. If you care about/want to set Recovery back up, you can create a recovery partition using the info in this page.
For this exercise, I’m going to assume there is ample space on the source image. To make this even more apparent, I’m going to create the new VHDX as a 30GB disk. I’m also going loopback mount it, find the disk number it’s mounted at, and get a few free drive letters I can work with. You should of course do appropriate sizing! From the elevated PowerShell prompt, run the following:
# Create a new VHDX
New-VHD .\migrated.vhdx –Dynamic –Size 127GB
# Mount the new VHDX
Mount-DiskImage C:\Working\migrated.vhdx
# And find the mounted VHDX
$Target = Get-DiskImage C:\Working\migrated.vhdx
# And find the disk number of the mounted VHDX on the parent partition
($Target | Get-Disk).Number
Use Explorer to get 3 free disk letters.
From the output of the above commands, in my case the drive number is 2, and the three drive letters are X:, Y: and Z:.
Now it’s time to create a diskpart script to partition the new VHDX. It is REALLY IMPORTANT to make sure you insert the right disk number, otherwise you risk losing all data on another disk on your system. For that reason, I’m not even going to put a number in the script below in case someone comes along and runs it. Here’s my script using drive letters X:, Y: and Z:. Save it as vhdx-setup.txt
Note this is adapted from this page - I have just removed the recovery partition setup. As the machines I am doing this on will never have Bitlocker enabled, we can simply enable the Recovery tools and it’ll default to the primary partition.
select disk INSERT_YOUR_DISK_NUMBER_HERE
clean
convert gpt
create partition efi size=100
format quick fs=fat32 label="System"
assign letter=Y
create partition msr size=16
create partition primary
format quick fs=ntfs label="Windows"
assign letter=Z
list part
Next, partition your disk (again heed warning about the potential for data loss) by running the following from an elevated command prompt:
diskpart /s vhdx-setup.txt
If all is good, you should see output similar to the following from the command prompt, and the drive letters showing up in Explorer.
At this point, we’re going to put or ‘apply’ the captured image from the source VHDX into the Windows partition on the new VHDX, drive letter Z: in my walkthrough. Run the following from an elevated command prompt:
dism /apply-image /imagefile:captured.wim /applydir:z:\ /index:1
#todo image
This will take some time depending on the size of the capture image and your storage subsystem performance.
Now we need to configure the ESP (EFI System Partition) on the target VHDX. Run the following from an elevated command prompt, where Z: is the target Windows partition and Y: is the target ESP. To be safe, it would be prudent to running bcdboot from the source operating system, not the one on the parent partition, just in case of incompatibilities.
Z:\Windows\System32\bcdboot Z:\Windows /s Y: /f UEFI
#todo image
At this point, let’s do a quick recap of where we are. We have
drive letter will be stuck til reboot
dismount-diskimage migrated vdhx
make new gen 2 vm
use new vhdx
boot and happy
fix recovery