Monday, January 21, 2013

Building A Hyper-V Test Lab on Windows 8 – Part 3 Creating VMs

This the third part in a multi-part set of articles. See the first article for the start of the set and to understand better what this is all about – see here: And to see the prior article on creating a reference VHDX see here:
Building a VM
The overall purpose of my VM Build scripts is to create and configure a set of VMs in a test environment. In the last article, I showed how you can create a base or reference disk. In this article, I show how you can take that base disk and create both a differencing disk and a VM that uses that new disk.
Each VM created gets a customised Unattend.XML file, which is stored on the differencing disk, once that disk is created. Thus, when the VM is started, OS installation is completed using the XML file. This allows me to do some simple things, like kill the firewall, set the right language(s), etc.  Creating this file was one of my early stumbling blocks!
From the earliest days of Windows NT, you could create an Unattend.txt file, put it on a floppy disk, insert the floppy into your system then install the OS from the CD. That enabled Windows NT setup to get the details of the installation coming from the Unattend.Txt. I did a lot of that in then NT 3.5/3.51/4.0 days. But with Vista, Microsoft shipped a totally new setup method, with WIM files and with Unattend.txt replaced with (a more complex) Unattend.XML. Pretty much everything I knew about unattend.txt files goes out the window.
A key objective I had in creating these build scripts was to avoid having to know too much about these XML files. I got a ‘starter’ copy form my good pals at Lab Center in Stockholm and have tweaked it (removing things I don’t need) and creating useful default settings for things (e.g. keyboard).
I really wanted to avoid becoming a deployment wizard and use a generic Unattend.XML file. But sadly, that objective proved to be a little unreasonable, but I’ve tired hard to minimise the number of things configured in the XML file and do as much as I can via PowerShell scripts after the OS has been installed.
Using Unattend.XML files is pretty simple, as long as you understand both the Windows build model and the components you can add to windows. To use the Unattend.XMO file, you create/configure the XML file, save it on the differencing disk and add the differencing disk to the VM. This way, the unattend.XML file guides Windows Setup to create the VM as you need it.  Subsequent scripts that configure the VM further (e.g. adding application specific windows component, adding applications and features, etc.).
In the Unattend.XML file, I currently specify 14 components in three passes as follows



The effect of this component

Generalize Microsoft-Windows-Shell-Setup Specifies that Sysprep should not remove any icons from the Quick Launch toolbar
Specialize Microsoft-Windows-UnattendedJoin Specifies the domain to join and credentials needed to join or whether to just ‘join’ a named workgroup
  Microsoft-Windows-Shell-Setup Specifies Computer name, registered organsiation and owner, and time zone
  Microsoft-Windows-IE-InternetExplorer Sets home page to blank and whether to disable the run-once wizard
  Microsoft-Windows-Deployment Enables local administrator account
  Microsoft-Windows-International-Core Specifies Input Locale, System Locale, UI Language and UserLocale. The input locale sets an initial keyboard layout.
  Microsoft-Windows-TapiSetup Tapi settings
  Microsoft-Windows-IE-ESC Turns off the IE security settings
  Microsoft-Windows-TerminalServices-LocalSessionManager Enables Terminal services connection to the VM
  Networking-MPSSVC-Svc Turns the firewall off on the VM
  Microsoft-Windows-TCPIP Sets TCP/IP settings, including IP address, subnet mask and default gateway
  Microsoft-Windows-DNS-Client Specifies the DNS Server IP address
OobeSystem Microsoft-Windows-Shell-Setup Specifies local administrator password, whether to hide the EULA pages plus sets the time zone
  Microsoft-Windows-International-Core Specifies a 2nd language to be setup for this VM
The Create-VM function
The core aspects of the VM creation is done with the Create-VM function. The function takes parameters including the VM name, the path to store the VM information for Hyper-V, the path to the reference disk, what network to use, how much memory to set, which Unattend.XML file to use and the IP address, subnet mask and DNS Server Address.
The details of the VM created is determined by what is in the Create-VM function, details in the the Unattend.XML file and some details set by the call to the create-VM function. For example, the keyboard settings used are set in the XML file only, whereas the use of dynamic memory is set only in the Create-VM function. The IP address, on the other hand, has a default set  in the XML ( The Create-VM function, however, overwrites this address with the IP address/subnet mask specified  in the call to Create-VM.  The parameters specified on the call to Create-VM are used to update the Unattend.XML file stored on the differencing disk and used to install the OS.
I use two XML files – one is used to create a stand alone server the other to create a domain joined server. I use the former to create DC1 and once DC1 has been promoted to be a DC, the later XML file is used to create servers that are domain joined. Both XML files, on the other hand, set keyboard layout
This approach of setting some installation options in the XML and others via the function (and resulting in updated XML) seemed to be a good compromise. I only implement parameters to Create-VM that need to be differ3ent in different VMs, whereas installation options
Creating the VM
The task of creating/building the VM is performed by the Create-VM function and involves the following steps:
  1. Creating a differencing disk – this is the ‘difference’ between a reference or parent Vhdx  and  the disk. 
  2. Creating a VM in Hyper-V.
  3. Adding the differencing disk into the VM.
  4. Mounting the VHD on the host computer.
  5. Based on a pre-built Unattend.XML, creating a customised Unattend.XML file and saving it to the on the mounted VHDX.
  6. Dismounting the VHDX from the host
  7. Setting VM settings including memory, startup actions etc.
  8. Starting the VM.

Once the VM has started, windows setup proceeds to install Windows as per the Unattend.XML file. The creation of the VM itself takes just 20-30 seconds, followed by the actual installation which takes 10-15 more minutes (and more if you are doing multiple installations in parallel).

The Created VM
The VM created by the Create-VM function will either be a workgroup VM or a VM that has been joined to the domain, as specified in the Unattend.XML file. This VM will be fairly vanilla with only a few options specified (as noted above). There are no extra applications loaded, and the file only ‘works’ once you have the DC up and running.

The Create-VM script takes around 27-30 seconds to create and start the VM in Hyper-V. On my WIn8 laptop, it take a further 5 minutes to complete the creating of the first DC.

Once you have the reference disk, you can call the Build-VM function like this:

$ref    = …   # Path to the reference disk
$Path   = …   # Path to where to put the VM and differencing disk
$unadj  = …   # Path to Unattend.XML
#     Now Create the VM
Create-VM -Name "Srv1"  -VmPath $Path –ReferenceVHD $Ref  -Network "Internal" `
          -UnattendXML $unadj -Verbose -IPAddr '' `
          -DNSSvr  -VMMemory 512mb

You run this script ON the Hyper-V server. Once the Create-VM function completes, which takes between 20-25 seconds in my case, Hyper-V starts up the VM and completes the installation of the OS inside the VM. The complete installation takes 20 minutes or so (depending on your system, how much RAM you give the VM, the speed of your system, etc.). Once the setup is complete, you can move on and configure the VM with application and application settings.

Where are we on this journey?
In the these first three blog posts, I’ve set out the objectives of a VM Build module for building VMs and the two core functions/scripts. The two scripts create a base VM disk, a differencing disk and a VM. Each VM is customised a little in the call to Create-VM – in effect creating a base VM. Once this VM has been created, you can then load additional applications and Windows features (e.g. making the DC a certificate authority). In the next episodes of this set of blog articles, I’ll start looking at the scripts that add those applications and features. And I’ll share the interesting things I’ve discovered along the way. I’ll also publish the scripts and the unattended XML files.




Technorati Tags: ,,


Yuejun Sun said...

after created the vm, failed to set the ip as expected.

Thomas Lee said...

That suggests that the editing of the XML file did not work - check file permissions and that all the files are in the right place. Run the script in debug mode, line at a time. THese scripts run perfectly as long as everything is in the right places!

Yuejun Sun said...

I found the reason. Eithernet, this parameter caused the issue. added the following code:
#changed the VM's mac
Get-VM -Name $Name | Get-VMNetworkAdapter | Set-VMNetworkAdapter -StaticMacAddress $mac

#change VM's identifier as max with Hex format
$tcpip = $xml.unattend.settings.component | Where-Object { $_.Name -eq "Microsoft-Windows-TCPIP" }
$tcpip.Interfaces.Interface.Identifier = $macWithDash

with changed above, it works.