This post is part of a series of posts about buidling a lab environment using some of the new PowerShell cmdlets and features in Windows 8.

In the previous post I explained how to create a virtual disk, apply a standard Windows Server 2008 image to it and attach the disk to a new VM. If you followed my steps you should have noticed that it was not a fully automated experience. During the installation I was asked to provide the regional settings, set or skip a license key, accept the EULA and provide an administrator password. And when I finally was logged in I still had to do a lot of configuration like setting an ip-address and renaming the machine. In this post we will get these steps out of the way as well.

The first step is to do some primary settings. In my case I enable PowerShell and Remote Desktop. This is also a good time to download updates and .NET frameworks you might need later. Try to keep things as basic as possible. Only set the ip-address if that's needed. We will change it later on.

Once the machine is to your liking it's time to sysprep it. Sysprep is located in the sysprep folder inside the system32 folder. Sysprep removes all personal information from the machines and makes it possible to create an image for redeployment. Start sysprep and choose OOBE Experience, Shutdown and make sure the box at Generalize is checked or better run it from the commandline: sysprep /generalize /oobe /shutdown. Make sure you specify the generalize option. This will create a new machine identifier for every machine. If you miss that one you could get into weird problems.

After sysprep is done it shuts down the machine. Now it's time to create an image that we can use as a base for deployement. You only have to do this once for every base image you want to create. I'm using a Windows 2008 and Windows 2008 Core template. Using DISM you can create an image (WIM) file. First you need to mount the image using Mount-VHD <pathtovhd>. Now capture the image with: DISM.exe /Capture-Image /ImageFile:D:\vm\base.wim /CaptureDir:G:\ /name:Base-Image. Replace the paths and name with your own. After some time a file is created. Make sure to dismount the vhd using Dismount-VHD. This concludes step 1 of this task. Next up is to automate the installation. There is an easy way and a hard way. The easy way is to use the Windows Automation Installation Kit. This tool has an editor to create unattended files. Another option is to create one with notepad. Of course you can also copy from others. Here is an example of the unattend.xml I'm using to create a domain controller. Read through it, I will explain the values in a moment.

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="specialize">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\
<ComputerName>DC-01</ComputerName>
<TimeZone>UTC</TimeZone>
<RegisteredOrganization>Contoso Corp.</RegisteredOrganization>
<RegisteredOwner>Contoso Corp.</RegisteredOwner>
<ProductKey>7P8GH-FV2FF-8FDCR-YK49D-D7P97</ProductKey>
</component>
<component name="Microsoft-Windows-DNS-Client" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="NonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Interfaces>
<Interface wcm:action="add">
<DNSServerSearchOrder>
<IpAddress wcm:action="add" wcm:keyValue="1">127.0.0.1</IpAddress>
</DNSServerSearchOrder>
<Identifier>Local Area Connection</Identifier>
</Interface>
</Interfaces>
</component>
<component name="Microsoft-Windows-TCPIP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Interfaces>
<Interface wcm:action="add">
<Ipv4Settings>
<DhcpEnabled>false</DhcpEnabled>
<Metric>10</Metric>
<RouterDiscoveryEnabled>false</RouterDiscoveryEnabled>
</Ipv4Settings>
<Identifier>Local Area Connection</Identifier>
<UnicastIpAddresses>
<IpAddress wcm:action="add" wcm:keyValue="1">192.168.200.1/24</IpAddress>
</UnicastIpAddresses>
<Routes>
<Route wcm:action="add">
<Identifier>1</Identifier>
<Metric>10</Metric>
<NextHopAddress>192.168.200.1</NextHopAddress>
<Prefix>0.0.0.0/0</Prefix>
</Route>
</Routes>
</Interface>
</Interfaces>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<InputLocale>132105</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<OOBE>
<HideEULAPage>true</HideEULAPage>
</OOBE>
<UserAccounts>
<AdministratorPassword>
<Value>p@ssw0rd</Value>
<PlainText>true</PlainText>
</AdministratorPassword>
</UserAccounts>
</component>
</settings>
<settings pass="windowsPE">
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<UserData>
<AcceptEula>true</AcceptEula>
</UserData>
</component>
</settings>
</unattend>

There are several sections in the xml. One section is the pass phase. This tells the setup routing at what point to use the settings. Some settings are only valid in one phase while other can be in multiple. The Windows Automation Kit knows and will only choose the right ones.

In the first part of the file the computer name is set along with the time zone and other details. The product key is not a real key but a temporary one. It's actually the same key that's entered when you click skip during the setup process. You can find this key inside a file in the Windows installation dvd. So, it's not a real key, just one that will get the setup process automated.

In the second part the network is set. In this example the ip 192.168.200.1 is used with netmask 255.255.255.0. The DNS is set to 127.0.0.1 because this machine will take the role of domain controller with DNS installed. The gateway is set to the 192.168.200.1 as well.

The last part is where the locale settings are set. The values can be retrieved from this table. Also the EULA is accepted and the administrator password is set. If you use the Windows Automation Kit the password will be encrypted. As a best practice you should not include the password in plain text.

So far for preparation, now it's show time. The trick is to get the unattend.xml we created located at the rootdrive of the machine. Using PowerShell and the commands from the previous post this task is easy. As you might recall I mounted the disk to apply the image and set the bootrecords. Run through the steps from the first post up until the point where the drive is dismounted. With the disk still mounted you can copy whatever file you want to the drive, including an unattend. If you add this PowerShell one-liner before you dismount the disk the file will be copied: Copy-Item source destination –force. This will copy the file from A to B. Now dismount the disk and you are done.

Once the autounattend is copied you can start the VM. After a few minutes and with no user interaction you should be able to log into the machine.

This brings us one step closer to a complete unattended installation of a lab environment. In the next post I will explain how to perform post install actions like installing and configuring AD and setting up SQL Server.