I am using Hyper-V again to setup a lab on one of my laptops. Most of the VMs are going to be Server 2012 (GUI or Core) and rather than “waste” space for each VM I decided to create a base VHD and use.
Generation 1 VM only!
The steps below only work for a Generation 1 VM. If you want to use a Generation 2 VM read this post to get an idea of what I am doing, but don’t follow all the steps. Instead, check out my next post where I go into UEFI and GPT and the boot process there, and follow the steps there.
Using the VHD created below in a Generation 1 VM gives the following error when booting: Boot failed. EFI SCSI Device. No Operating System was Loaded. Press a key to retry the boot sequence ...
Here’s how I went about doing it. (None of this is new material, the below is just notes to my future self). Also, all these steps are on my Windows 8.1 with Update laptop, so it might not work on older versions of Windows (I know for sure that these won’t work on Windows 7).
First, mount the Server 2012 ISO:
1 2 3 4 5 |
PS D:\NoBackup> Mount-DiskImage -ImagePath E:\en_windows_server_2012_r2_x64_dvd_2707946.iso -PassThru | Get-Volume DriveLetter FileSystemLabel FileSystem DriveType HealthStatus SizeRemaining Size ----------- --------------- ---------- --------- ------------ ------------- ---- F IRM_SSS_X64FR... UDF CD-ROM Healthy 0 B 3.98 GB |
The ISO is mounted at F: drive. The sources\install.wim
file in this drive contains the WIM file with all the Server 2012 images. A WIM file (short for “Windows IMaging” file) is a file-based image. Unlike a block-based image (which is what most of us are familiar with from tools such as Ghost) a file-based image contains the files and file-system as it. In addition to that the files are compressed, and duplicate file names point to one actual file, so you could have a WIM file that contains all the editions of Server 2012 but the size of the WIM file isn’t equal to the size of one of these multiplied by the number of editions. Since Vista WIM files are what Microsoft’s been using to install the OS. The install program sets up your hard disk and then dumps a WIM file onto it. After a reboot, the machine boots into this dumped image and continues configuring and customizing.
The beauty of this is that one can dump a specified image from a WIM file onto a virtual hard disk too – which is what I am going to do here. I select an image from my WIM file, create a VHD file, and apply this image to the VHD file. Then when I boot up from this VHD file in a newly created VM the setup process continues as it is. The difference here is that I am going to apply to the image to a VHD file, and then use that VHD file as a base image and create new “differencing” VHD files off that. This way each newly created VM uses the differencing VHD file, and the size of that is more or less equal to the changes I make in the VM. That’s way better than having multiple VHD files all of which contain the same OS and similar files and together take up a lot of space!
Back to the WIM file, find the image that we are interested in:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
PS D:\NoBackup> Get-WindowsImage -ImagePath F:\sources\install.wim Index : 1 Name : Windows Server 2012 R2 SERVERSTANDARDCORE Description : Windows Server 2012 R2 SERVERSTANDARDCORE Size : 6,836,711,203 bytes Index : 2 Name : Windows Server 2012 R2 SERVERSTANDARD Description : Windows Server 2012 R2 SERVERSTANDARD Size : 11,676,579,164 bytes Index : 3 Name : Windows Server 2012 R2 SERVERDATACENTERCORE Description : Windows Server 2012 R2 SERVERDATACENTERCORE Size : 6,837,191,915 bytes Index : 4 Name : Windows Server 2012 R2 SERVERDATACENTER Description : Windows Server 2012 R2 SERVERDATACENTER Size : 11,676,661,826 bytes |
I am interested in the first image here (Serer 2012 R2 Standard Core). I want to apply this image to a VHD. So I create a 20GB VHDX file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
PS D:\NoBackup> New-VHD '.\Hyper-V\Virtual Hard Disks\2012r2.vhdx' -SizeBytes 20GB -Dynamic ComputerName : TINTIN Path : D:\NoBackup\Hyper-V\Virtual Hard Disks\2012r2.vhdx VhdFormat : VHDX VhdType : Dynamic FileSize : 4194304 Size : 21474836480 MinimumSize : LogicalSectorSize : 512 PhysicalSectorSize : 4096 BlockSize : 33554432 ParentPath : DiskIdentifier : 9fcb90d4-56a8-4d94-9fb8-767717cf4547 FragmentationPercentage : 0 Alignment : 1 Attached : False DiskNumber : Key : IsDeleted : False Number : |
Mount the VHDX file:
1 2 3 4 5 |
PS D:\NoBackup> Mount-VHD -Path '.\Hyper-V\Virtual Hard Disks\2012r2.vhdx' -Passthru | Get-Disk Number Friendly Name OperationalStatus Total Size Partition Style ------ ------------- ----------------- ---------- --------------- 3 Microsoft Virtual Disk Online 20 GB RAW |
Note that I use Get-Disk
above. That’s because the VHDX doesn’t have a file system yet, and hence no volume. I will have to prepare the VHDX before I can apply the previous WIM image onto it. So let’s do that.
Create a partition and format it as NTFS. Assign a drive label while we are at it.
1 2 3 4 5 6 |
PS D:\NoBackup> Initialize-Disk -Number 3 -PartitionStyle MBR PS D:\NoBackup> New-Partition -DiskNumber 3 -UseMaximumSize -IsActive -AssignDriveLetter | Format-Volume -FileSystem NTFS -Confirm:$false -NewFileSystemLabel 2012R2-STD-CORE DriveLetter FileSystemLabel FileSystem DriveType HealthStatus SizeRemaining Size ----------- --------------- ---------- --------- ------------ ------------- ---- G 2012R2-STD-CORE NTFS Fixed Healthy 19.94 GB 20 GB |
NOTE: It is possible to combine all the cmdlets above from New-VHD
to Format-Volume
into one long pipe. That way easier to copy paste than the multiple cmdlets above. Here’s the combo version:
1 2 3 4 5 6 7 |
PS D:\NoBackup\> New-VHD -Path '.\Hyper-V\Virtual Hard Disks\2012r2-std-gui.vhdx' -SizeBytes 20GB -Dynamic | Mount-VHD -Passthru | Initialize-Disk -PartitionStyle MBR -PassThru | New-Partition -UseMaximumSize -AssignDriveLetter -IsActive | Format-Volume -FileSystem NTFS -Confirm:$false -NewFileSystemLabel 2012R2-STD-GUI -Force DriveLetter FileSystemLabel FileSystem DriveType HealthStatus SizeRemaining Size ----------- --------------- ---------- --------- ------------ ------------- ---- H 2012R2-STD-GUI NTFS Fixed Healthy 19.94 GB 20 GB |
Now I apply the WIM image to this drive letter (which is actually the VHDX file I created earlier):
1 |
PS D:\NoBackup> Expand-WindowsImage -ImagePath .\2012r2.wim -Index 1 -ApplyPath G: |
This cmdlet will take a while to complete (and it doesn’t offer much by way of a progress bar)
NOTE: You can use the DISM command too instead of the cmdlet above. That has a more informative progress bar:
1 2 3 4 5 6 7 8 |
PS D:\NoBackup> dism /apply-image /imagefile:2012r2.wim /index:1 /applydir:G:\ Deployment Image Servicing and Management tool Version: 6.3.9600.17031 Applying image [==========================100.0%==========================] The operation completed successfully. |
Install a boot loader on the VHD so it boots.
1 2 |
PS D:\NoBackup> bcdboot.exe G:\Windows /s G: /f BIOS Boot files successfully created. |
Don’t forget the boot loader!
I had missed this step when I first wrote this post. Apologies if anyone followed the steps and ended up with non-bootable VHD. I realized this omission only after I tried booting the VHD and got the following error:
Finally dismount the VHDX:
1 |
PS D:\NoBackup> Dismount-VHD '.\Hyper-V\Virtual Hard Disks\2012r2.vhdx' |
Dismount the ISO file too if you are done with it:
1 |
PS D:\NoBackup> Dismount-DiskImage -ImagePath E:\en_windows_server_2012_r2_x64_dvd_2707946.iso |
Finally, I make a new differencing VHD:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
PS D:\NoBackup> New-VHD -Path '.\Hyper-V\Virtual Hard Disks\WINDC01.vhdx' -ParentPath '.\Hyper-V\Virtual Hard Disks\2012r2-core.vhdx' -Differencing ComputerName : TINTIN Path : D:\NoBackup\Hyper-V\Virtual Hard Disks\WINDC01.vhdx VhdFormat : VHDX VhdType : Differencing FileSize : 4194304 Size : 21474836480 MinimumSize : 21474836480 LogicalSectorSize : 512 PhysicalSectorSize : 4096 BlockSize : 2097152 ParentPath : D:\NoBackup\Hyper-V\Virtual Hard Disks\2012r2-core.vhdx DiskIdentifier : 9fcb90d4-56a8-4d94-9fb8-767717cf4547 FragmentationPercentage : Alignment : 1 Attached : False DiskNumber : Key : IsDeleted : False Number : |
That’s it. Now I can create a VM and assign the WINDC01.vhdx disk to it. As far as the VM (or even us if we mount the VHDX file directly) are concerned the WINDC01.vhdx file is identical to the 2012R2.vhdx file it is based up. Just that what the file actually contains is only the differences from the base file. Any references to files in the base VHD file are looked up there transparently; any references to new/ changed files are looked up in the differencing VHD file.
Generation 1 VM only!
As mentioned at the beginning of this post, the VHDX file created using the above steps only works with a Generation 1 VM. With a Generation 2 VM you get an error like this:
This is because Generation 2 VMs are using UEFI and they have a different boot process. Check my follow-up post on what to do with a Generation 2 VM. .