Learn about Windows PowerShell
Summary: Use the freely available Convert-WindowsImage.ps1 to extract multiple bootable VHD files for Hyper-V Server 2012 R2.
Hey, Scripting Guy!
Is there an easier way to create a VHD file that already has the operating system, rather than installing it and clicking Next…Next…Next? I’d like something that could spin up a simple machine like it was a template.
Honorary Scripting Guy, Sean Kearney, is here. Funny you should ask. I was poking about with that idea the other day. I decided for a good simple lab, I would need the following:
Ideally this solution, as I was thinking to myself, could even potentially leverage Windows Powershell Desired State Configuration in the long term. More importantly, I wanted something that could be simple enough that a person with minimal knowledge of Windows PowerShell could easily use to spin up machines.
I will make some important notes. Although this solution is targeted to use the free tools, it works equally well in the full versions of Windows Server 2012 R2 and Windows 8.1. It might work with Windows Server 2012, but I haven’t tested it yet. Theoretically, it should all work.
So a few pieces came together. For software, I opted for the following free tools from Microsoft and the IT community.
Hyper-V Server 2012 R2
Free hosting environment for virtual machines from Microsoft
Evaluation version of Windows Server 2012 R2
180-day trial of Windows Server 2012 R2 as an operating system for the virtual machines
Free script written by a Microsoft partner, Pronichkin, to directly convert a WIM file to a bootable VHD. This is a great tool!
I’m going to presume that you at least know how to setup Hyper-V. If you download the free version, you’ll need to run sconfig to configure the environment. It is a really nice easy-to-use VBScript script that does all the nasty work. You’ll also have to remember that it defaults to Cmd.exe, and you will have to launch Powershell.exe to execute all of your scripts.
If you’re curious about trying to get a Hyper-V environment initially configured, here’s a series I wrote a while back on TechNet that will give you some tips: Hyper-V and the Windows PowerShell Cmdlets.
So with the presumption you have a server running Hyper-V, our first task is to get all those goodies out of the WIM file. I want to avoid typing anything as much as possible. I would also like the VHD files that I create to reflect the version of the server.
Within the latest Windows Server environments, there is a built-in cmdlet called Mount-DiskImage, which will allow us to mount either an ISO file or a VHD file directly from Windows PowerShell, and then access its contents.
MOUNT-DISKIMAGE –imagepath $ISO
This is all good. But it doesn’t return the drive letter of the mounted VHD or ISO file. You can obtain this by using two other cmdlets, which we pipe together for this information:
GET-DISKIMAGE –imagepath $ISO | GET-Volume
If we need only the drive letter, we’ll access the property directly and store it away:
$DriveLetter=((GET-DISKIMAGE –imagepath $ISO | GET-Volume).DriveLetter)+”:”
Now with the drive letter in a scriptable state, we need to get some information about the WIM file. We need to know how many images are in the WIM file and the descriptions for each image. We will leverage this information when launching the Convert-WindowsImage.ps1 file.
To get this information, we can leverage the Get-WindowsImage cmdlet from the DISM module. We target the WIM file, and it will return a list of images, their index numbers, and descriptions for it:
GET-WINDOWSIMAGE –ImagePath ($DriveLetter+”\sources\install.wim”)
Now we’ll capture that information to make it useful by storing it away:
$Images=GET-WINDOWSIMAGE –ImagePath ($DriveLetter+”\sources\install.wim”)
This is where the fun begins. We’re going to make some bootable VHDs. The Convert-WindowsImage command needs to be provided only three pieces of information to make it useful:
A simple example of the script in action would be this:
CONVERT-WindowsImage.PS1 –sourcepath install.wim –VHDPath c:\vhds\filename.vhd –edition ServerDataCenterCore
Or if we’re going to specify the index number (same version here too):
CONVERT-WindowsImage.PS1 –sourcepath install.wim –VHDPath c:\vhds\filename.vhd –edition 3
We already know the name and location of the WIM file. Now we start up a nice FOR loop, step through the images:
FOREACH ($Image in $Images)
...and grab the index number:
If only I could remove the spaces from the description and make that into a file name…
Oh, right! I’m in Windows PowerShell! I can! We’ll grab the description first:
…and then use the Replace method to remove the spaces:
Then add our destination location and file extension to our new name:
And with one-fell swoop, launch the script to create a bootable VHD from a WIM file entry:
C:\ISO\Convert-WindowsImage.PS1 –sourcepath “$Driveletter\Sources\Install.wim” –Edition $Index –VHDPath $VHDName
Save this file into a folder. In this post, I am referencing C:\ISO, which is where I wrote this environment from. Make that location and save it there for ease-of-use. I called my CREATE-VMTemplate.PS1.
Place the Convert-WindowsImage.ps1 and CREATE-VMTemplate.PS1 in this folder and execute CREATE-VMTemplate.PS1:
Watch…and in about 10 minutes (depending on the speed of your computer and hard disk), you’ll have a lovely pile of VHDs that look like this:
Come back tomorrow when we go to the next step and make an easier way to configure the VHD before attaching it to a virtual machine.
I invite you to follow The Scripting Guys on Twitter and Facebook. If you have any questions, send an email to The Scripting Guys at email@example.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then remember eat your Cmdlets each and every day with a taste dash of Creativity.
Sean Kearney, Windows PowerShell MVP and Honorary Scripting Guy
Also check the Automated Labs PowerShell script from Raimund Andrée. Cool stuff. http://gallery.technet.microsoft.com/AutomatedLab-026d81f9 Stefan Stranger - MSFT @sstranger
@Stefan Excellent! Thanks for sharing! :) Sean
In case anyone comes across it, it appears Microsoft set the sparse flag for the Server 2012 R2 eval iso. This means you won't be able to use Get-DiskImage or Mount-DiskImage against it... As a workaround, you could copy it, which removes the sparse flag.
fsutil sparse queryflag
Use vhdx 😊