If you are creating unattended.xml files to use to perform automated installations of windows then you will at some point want to test it. This is fine if the destination system has a keyboard and monitor but in my case the system I am targeting does not, a HP MediaSmart EX490.
The simplest way I found on Windows 8 to do the testing was to use the Hyper-V role. Normally I prepare a USB stick with the Microsoft USB/DVD Download Tool and then copy the autounattend.xml file to the root of the USB disk. However, during installation Windows will search for an autounattend.xml or unattend.xml on other removable devices. Using this we can setup a Hyper-V VM with two DVD drives. One with the installation media in the other with just the autounattend.xml
I found on the internet a PowerShell script, New-IsoFile that will create an ISO from a list of files. Credit goes to Chris Woo and information can be found at http://gallery.technet.microsoft.com/scriptcenter/New-ISOFile-function-a8deeffd
Below is my PowerShell script that I use. Basically it uses Chris’s New-IsoFile function to create an ISO with the autounattend.xml file in it. It then creates a VM, attaches the Installation ISO (in this case Hyper-V Server) and the answer file ISO and starts the VM.
function New-IsoFile {
<#
.Synopsis
Creates a new .iso file.
.Description
The New-IsoFile cmdlet creates a new .iso file containing content from chosen folders.
.Example
New-IsoFile "c:\tools", "c:\Downloads\utils"
Description:
This command creates a .iso file in the $env:temp folder (default location) that contains
c:\tools and c:\downloads\utils folders. The folders themselves are added to the root
of the .iso image.
.Example
dir c:\WinPE | New-IsoFile -Path c:\temp\WinPE.iso -BootFile etfsboot.com -Media DVDPLUSR -Title "WinPE"
Description:
This command creates a bootable .iso file containing the content from the c:\WinPE folder,
but the folder itself isn't included. Boot file etfsboot.com can be found in Windows AIK.
Refer to IMAPI_MEDIA_PHYSICAL_TYPE enumeration for possible media types:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366217(v=vs.85).aspx
.Notes
NAME: New-IsoFile
AUTHOR: Chris Wu
LASTEDIT: 03/06/2012 14:06:16
#>
param (
[parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] $Source,
[parameter(Position=1)] [string] $Path = "$($env:temp)\" + (Get-Date).ToString("yyyyMMdd-HHmmss.ffff") + ".iso",
[string] $BootFile = $null,
[string] $Media = "Disk",
[string] $Title = (Get-Date).ToString("yyyyMMdd-HHmmss.ffff"),
[switch] $Force
)
begin {
# Compiler setup
$cp = New-Object System.CodeDom.Compiler.CompilerParameters
$cp.CompilerOptions = "/unsafe"
# Add the ISOFile type if it doesn't exist
if (!("ISOFile" -as [type])) {
Add-Type -CompilerParameters $cp -TypeDefinition @"
public class ISOFile {
public unsafe static void Create(string Path, object Stream, int BlockSize, int TotalBlocks) {
int bytes = 0;
byte[] buf = new byte[BlockSize];
System.IntPtr ptr = (System.IntPtr)(&bytes);
System.IO.FileStream o = System.IO.File.OpenWrite(Path);
System.Runtime.InteropServices.ComTypes.IStream i = Stream as System.Runtime.InteropServices.ComTypes.IStream;
if (o == null) { return; }
while (TotalBlocks-- > 0) {
i.Read(buf, BlockSize, ptr);
o.Write(buf, 0, bytes);
}
o.Flush();
o.Close();
}
}
"@
}
# Boot file setup
if ($BootFile -and (Test-Path $BootFile)) {
$Stream = New-Object -ComObject ADODB.Stream
$Stream.Open()
$Stream.Type = 1 # adFileTypeBinary
$Stream.LoadFromFile((Get-Item $BootFile).Fullname)
$Boot = New-Object -ComObject IMAPI2FS.BootOptions
$Boot.AssignBootImage($Stream)
}
# Media type mapping
$MediaType = @{
CDR = 2; CDRW = 3; DVDRAM = 5; DVDPLUSR = 6; DVDPLUSRW = 7;
DVDPLUSR_DUALLAYER = 8; DVDDASHR = 9; DVDDASHRW = 10; DVDDASHR_DUALLAYER = 11;
DISK = 12; DVDPLUSRW_DUALLAYER = 13; BDR = 18; BDRE = 19
}
if ($MediaType[$Media] -eq $null) {
Write-Debug "Unsupported Media Type: $Media"
Write-Debug ("Choose one from: " + $MediaType.Keys)
break
}
# Image setup
$Image = New-Object -ComObject IMAPI2FS.MsftFileSystemImage -Property @{ VolumeName = $Title }
$Image.ChooseImageDefaultsForMediaType($MediaType[$Media])
# File validation
if ((Test-Path $Path) -and (!$Force)) {
Write-Host "File Exists: $Path"
break
}
$Target = New-Item -Path $Path -ItemType File -Force
if (!$Target) {
Write-Host "Cannot create file: $Path"
break
}
}
process {
switch ($Source) {
{ $_ -is [string] } { $Image.Root.AddTree((Get-Item $_).FullName, $true); continue }
{ $_ -is [IO.FileInfo] } { $Image.Root.AddTree($_.FullName, $true); continue }
{ $_ -is [IO.DirectoryInfo] } { $Image.Root.AddTree($_.FullName, $true); continue }
}
}
end {
if ($Boot) {
$Image.BootImageOptions = $Boot
}
$Result = $Image.CreateResultImage()
[ISOFile]::Create($Target.FullName, $Result.ImageStream, $Result.BlockSize, $Result.TotalBlocks)
$Target
}
}
# Create a New VM based on autounattend.xml
$path = [Environment]::GetFolderPath("UserProfile") + "\Downloads"
$name = "Hyper-V Server 2012"
$switch = "vSwitch"
# Cleanup and setup
Stop-VM -Name $name -Force -TurnOff
Remove-VM -Name $name -Force
Remove-Item -Force $path\auto.iso
Remove-Item -Force $path\hyper-v.vhd
# Generate ISO
dir $path\autounattend.xml | New-IsoFile -Path $path\auto.iso -Media CDR -Title "Unattend"
# Create and configure the VM
New-VM -Name $name -SwitchName $switch
Set-VMProcessor -VMName $name -Count 1
Set-VMMemory -VMName $name -StartupBytes 2147483648
New-VHD -Path $path\hyper-v.vhd -SizeBytes 21474836480
Add-VMHardDiskDrive -VMName $name -Path $path\hyper-v.vhd -ControllerType IDE -ControllerNumber 0 -ControllerLocation 0
Set-VMDvdDrive -VMName $name -Path $path\en_microsoft_hyper-v_server_2012_x64_dvd_915600.iso -ControllerNumber 1 -ControllerLocation 0
Add-VMDvdDrive -VMName $name -Path $path\auto.iso -ControllerNumber 1 -ControllerLocation 1
# Start the VM
Start-VM -Name $name
Write-Host "When you press enter, the Virtual Machine will be stopped and deleted"
Pause
# Cleanup
Stop-VM -Name $name -Force -TurnOff
Remove-VM -Name $name -Force
Remove-Item $path\hyper-v.vhd
Remove-Item $path\auto.iso
Simply run the Script and Open the VM in Hyper-V Manager, you can then verify the automated install works and if not have an easier time of debugging the situation than if you were running on a headless system.