Make Your Windows 10 Computer Versatile

Make Your Windows 10 Computer Versatile by Using VHDX Native Boot

While working on a project the other day I found myself needing to install several tools. I really didn’t want to install the tools in my main, native Windows instance since I would only need them for the project. Since Windows doesn’t provide an easy way to roll back the entire system, I decided to explore a feature that has been part of Windows since Windows 7 – native booting from VHD(X). If you’re not familiar with the concept, it allows you to dual-boot a Windows system without having to deal with the messy and difficult concept of partitioning. You create a VHD(X) file in your normal, native Windows instance that contains a separate instance of Windows (possibly a different version), and then tell the boot loader to boot from the VHD(X) file instead of the normal C: drive.

For this project, I wanted to go a step further than booting from a virtual disk. I wanted to boot from a VHD(X) chain – the same as a virtual machine snapshot on your virtualization platform of choice. With this, I can have a read-only parent VHD(X) that I can use for multiple instances and read-write differencing disks or child VHD(X)es that will contain the differences from the parent disk. So, in the end, I’ll have a parent VHD(X) that contains Windows 10, and a differencing disk that contains the tools specific to this project, and the combination of the two VHD(X) files will make up the C: drive for the running Windows instance. This is the part that is more sparsely documented on the web, and the documentation that is available is typically outside of this context.

Some of you may wonder why I keep noting VHD(X) instead of VHD. VHD was a good first development of a Virtual Hard Disk specification but had some limitations such as a capacity limit of 2TB. While developing Hyper-V, Microsoft decided to create a new specification that exceeded the limitations of VHD. So, VHDX serves the same purpose but is more modern to properly handle the virtualization tasks IT needed/wanted. Some of the features of VHDX are a 64TB capacity, a 4K logical sector size (to increase performance), corruption protection and the ability to be shared (for cluster scenarios).

Windows 7 allowed you to boot from VHD but knows nothing about VHDX, which was introduced in the Windows 8 and Windows Server 2012 timeframe. So today, if you want to boot Windows 10 from a virtual disk file, you need to use VHDX. For the rest of this article, I’ll just be using VHDX since technically, VHD doesn’t apply.

Let’s dig into the weeds…

For this activity we’re going to need a few things:

Step 1

The first thing we need to do is the equivalent of a Windows install into a VHDX file. For this, take a look at Convert-WindowsImage.ps1 by Pronichkin, found in the Microsoft TechNet gallery. This script takes Windows to install media as input and outputs a VHDX file that contains the equivalent of what the installer would have done. Once complete you’ll have a VHDX file that is ready for first boot.

Before you run it, there’s a couple modification you need to make. The latest version of Windows 10 has a couple changes that break the script (as of 8/28/2018). If you want to read about the gory details, you can look at the Q and A tab of the same page. Download the script, launch PowerShell ISE *AS ADMINISTRATOR*, and open the script for editing. Make the following changes:

  • line 4207:
    from: $drive = $(Get-Partition -Disk $disk).AccessPaths[0]
    to:      $drive = $(Get-Partition -Disk $disk)[0].AccessPaths[0]
  • line 4216:
    from: $driveSystem = $(Get-Partition -Disk $disk).AccessPaths[1]
    to:      $driveSystem = $(Get-Partition -Disk $disk)[1].AccessPaths[0]
  • line 4220:
    from: $drive = $(Get-Partition -Disk $disk).AccessPaths[2]
    to:      $drive = $(Get-Partition -Disk $disk)[2].AccessPaths[0]
  • line 4229:
    from: $drive = $(Get-Partition -Disk $disk).AccessPaths[1]
    to:      $drive = $(Get-Partition -Disk $disk)[1].AccessPaths[0]

Save the file. Then, in the shell pane of ISE run the following:

PS C:\Windows\system32> cd <path to script>
PS C:\Users\jordahl\Downloads> Set-ExecutionPolicy Unrestricted -Scope LocalMachine
PS C:\Users\jordahl\Downloads> . .\Convert-WindowsImage.ps1

(That’s dot-space-dot-backslash at the start there)

Those commands changed the working directory to the directory where the script is located, loosened the script restrictions so we can actually run the script, and loaded the Convert-WindowsImage function into memory. Now we need to run the function, and the parameters could vary depending on what Windows installer disk you’re using. One quick note about the script – it doesn’t appear to like using a non-local paths.

If you’re using a normal, single edition install disk then use the following command:

PS C:\Users\jordahl\Downloads> Convert-WindowsImage -VHDFormat VHDX -SizeBytes 100GB -BCDinVHD NativeBoot -ExpandOnNativeBoot:$false -SourcePath <path to iso>\<iso Name>.iso -VHDPath <path to save vhdx>\<vhdx Name>.vhdx

If you’re using a multi-edition install disk, add the Edition parameter:

PS C:\Users\jordahl\Downloads> Convert-WindowsImage -VHDFormat VHDX -SizeBytes 100GB -BCDinVHD NativeBoot -ExpandOnNativeBoot:$false -SourcePath <path to iso>\<iso Name>.iso -Edition <edition> -VHDPath <path to save vhdx>\<vhdx Name>.vhdx

This process will take a while, and you should see something similar to the following output:

Windows(R) Image to Virtual Hard Disk Converter for Windows(R) 10
Copyright (C) Microsoft Corporation. All rights reserved.
Version 10.0.9000.0.amd64fre.fbl_core1_hyp_dev(mikekol).141224-3000 BetaINFO : Opening ISO en_windows_10_ent.iso…
INFO : Looking for D:\sources\install.wim…INFO : Image 3 selected (Enterprise)…
INFO : Creating sparse disk…
INFO : Attaching VHDX…
INFO : Disk initialized with GPT…
INFO : Disk partitioned
INFO : System Partition created
INFO : Boot Partition created
INFO : System Volume formatted (with DiskPart)…
INFO : Boot Volume formatted (with Format-Volume)…
INFO : Access path (E:\) has been assigned to the System Volume…
INFO : Access path (F:\) has been assigned to the Boot Volume…
INFO : Applying the image to VHDX. This could take a while…
INFO : Signing disk…
INFO : Image applied. Making image bootable…
INFO : Drive is bootable. Cleaning up…
INFO : Closing VHDX…INFO : Closing Windows image…
INFO : Closing ISO…
INFO : Done.

Step 2

The VHDX file now contains Windows in a state that’s similar to when the Windows installer is about to reboot into the newly installed OS. So we’re at the pre-first-boot stage. In this state, the newly installed Windows has not yet discovered hardware or installed specific drivers. If your plan is to be able to use this VHDX on multiple, heterogeneous platforms, now’s the time to copy it to an archive location where you can pull it from later.

Step 3

Let’s now move the VHDX file that you’ll use to boot your machine to a more dedicated place. In my case, I created a folder at C:\VHDs and use that as the home for the master VHDX as well as any children I create.

Step 4

Almost time for first boot. At this point, I’m believing that you’ve created a backup copy of the VHDX file somewhere else so that you can use the same master for multiple physical machines. Now it’s time to boot the local VHDX and make it machine specific. To do this we need to modify the boot configuration of the physical machine; specifically, we need to modify the BCD which stands for Boot Configuration Data. For this process, I use EasyBCD and the following process will document it. If you’d prefer to drop to the CLI and modify the BCD manually, you can find some good info on a similar process here.

After installing EasyBCD, launch it. If you’re on a newer machine, the first thing you’re greeted with is the following:

There are two modes that a machine can use to boot, Legacy BIOS and UEFI. New machines use UEFI and when in use that message will pop up. It doesn’t affect what we’re doing here, so we can click OK. If you’re curious, the Help button will give you all the details on the differences between the two modes with respect to configuring the BCD. After clicking OK you’re presented with the main window:

You’ll note that there’s a single entry in the BCD. Anytime I’m dealing with the booting process for a machine I want to be careful and create backups along the way. So the first thing we’ll do is to backup the current BCD. Click the BCD Backup/Repair button which presents this:

Enter a file path into the first File field under Backup and Restore Bootloader Settings and click Backup Settings. In the future, if you want to restore back to defaults, use the second File field and the Restore Backup button. One thing to note, AFTER CLICKING A BUTTON IN EasyBCD, WAIT FOR THE RESULT MESSAGE IN THE STATUS BAR OF THE WINDOW BEFORE MOVING ON!

Now we need to create the new entry for our parent VHDX file. Click the Add New Entry button:

EasyBCD can be used to configure boot for a lot of possibilities. We’re just going to use the bottom pane, specifically the Disk Image tab. Enter whatever name you want to be in the BCD, find the VHDX file you created and moved to its permanent home (C:\VHDs maybe?) and click Add Entry. After seeing the success message in the status bar, click on View Settings:

We now have two entries in our BCD. But wait! Our second entry is named correctly but it looks like it’s going to boot the same Windows instance as entry one. EasyBCD doesn’t show enough info here to be clear when it comes to booting from virtual disks. If you click on the Detailed (Debug Mode) radio button under Display Mode we’ll get a better view:

This view gives us the full path to our VHDX file, so it really IS different than entry one.

Step 5

Now’s the moment of truth! Time to boot into our new OS. During the reboot process you’ll see a new screen similar to the following before anything actually boots:

Click the entry for your VHDX. This will start the first boot process with the new Windows instance in the VHDX. Please note that THE FIRST BOOT PROCESS REQUIRES A REBOOT, AT WHICH POINT YOU NEED TO CLICK THE SAME ENTRY AGAIN so you don’t boot into your main Windows install. If you missed it, just reboot again and select your VHDX entry. Windows will take you through the normal post-install steps.

Once you’re up and running and at the desktop you’ll want to do a few things. At this point, you want to make any changes to the install that you want to persist with the parent OS. This could/should include some or all of the following:

  • Change the machine name
  • Install Windows updates
  • Install any applications that you would want in all your child VHDX instances

Basically, you want to make all permanent changes at this point. Changing things in this VHDX file later is problematic, so try to be thorough. Once complete, reboot back into your main, native Windows install.

Step 6

Now we’re going to create our VHDX chain. To do this we need to be at AN ADMINISTRATIVE COMMAND PROMPT. I’m going to use PowerShell. Once open, run disk part. Now here’s the trick. Using the following command we’ll be creating a child VHDX file that’s linked to the VHDX parent we just created:

create vdisk file=”c:\vhds\Windows 10 Child.vhdx” type=expandable parent=”c:\vhds\Windows 10 Parent.vhdx”

As a safeguard, let’s make our parent VHDX read-only. In Windows Explorer get the properties of your parent VHDX and check the Read-Only box and click OK.

Step 7

Now that we’ve got our chain created, we need to go tweak the BCD again. Go back into EasyBCD and this time we’re going to remove the parent VHDX entry and add an entry for our child VHDX.

This time when we look, the Overview mode properly shows the path to our Parent VHDX – odd! Moving along… Click the Edit Boot Menu button, highlight your Windows 10 Parent entry and click the Delete button:

Now click the Add New Entry button, enter whatever name you want to be in the BCD, find the child VHDX file you created (C:\VHDs maybe?) and click Add Entry.

Now we’ll go back to the Detailed view mode of View Settings and validate that our child is in the BCD:

Step 8

And we’re golden! Now you can restart into your new child VHDX file.

Anything you install from this point will be stored in your child VHDX. If you want to roll back to default, delete the child VHDX and create a new one. To avoid repeatedly going into diskpart, I’ve created an empty child that I just copy whenever I want a new environment.

Something to note that bit me. By default, when Windows boots a VHD(X) file natively, it tries to “expand” or allocate the entire size of the virtual disk on the physical disk. You’ll clearly notice it if you try to boot the VHDX and it blue screens saying there’s not enough disk space. In the Convert-WindowsImage script, there’s an ExpandOnNativeBoot parameter that I’ve used in the commands above so that you can run, essentially in thin provisioned mode. If that wasn’t set, or Microsoft changes code and things stop working after an update, that’s a good first place to start looking.

One more thing to note is the use of the BCDinVHD parameter that removes the BCD element from the VHDX. This will cause problems if you were to try to use this image with Hyper-V.

Please let me know how this works for you!