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 $env:temp folder (default location) that contains c:\tools and c:\downloads\utils folders. The folders themselves are added in 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 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 )#End Param Begin { ($cp = new-object System.CodeDom.Compiler.CompilerParameters).CompilerOptions = "/unsafe" 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(); } } "@ }#End If if ($BootFile -and (Test-Path $BootFile)) { ($Stream = New-Object -ComObject ADODB.Stream).Open() $Stream.Type = 1 # adFileTypeBinary $Stream.LoadFromFile((Get-Item $BootFile).Fullname) ($Boot = New-Object -ComObject IMAPI2FS.BootOptions).AssignBootImage($Stream) }#End If $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 = new-object -com IMAPI2FS.MsftFileSystemImage -Property @{VolumeName=$Title}).ChooseImageDefaultsForMediaType($MediaType[$Media]) if ((Test-Path $Path) -and (!$Force)) { "File Exists $Path"; break } if (!($Target = New-Item -Path $Path -ItemType File -Force)) { "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 switch }#End Process End { if ($Boot) { $Image.BootImageOptions=$Boot } $Result = $Image.CreateResultImage() [ISOFile]::Create($Target.FullName,$Result.ImageStream,$Result.BlockSize,$Result.TotalBlocks) $Target }#End End }#End function New-IsoFile # Begin script by Albal to create New-VM based on autounattend.xml - # Assumes all required files are in, and will be written to <USER>\Downloads # Change the below parameters if needed $path = [Environment]::GetFolderPath("UserProfile") + "\Downloads" $name = "Hyper-V Server 2012" $switch = "vSwitch" # Don't change anything below this line - ignore the errors below, just in case you run the script again without having exited expectedly Stop-VM -Name $name -Force -TurnOff Remove-VM -Name $name -Force del -Force $path\auto.iso del -Force $path\hyper-v.vhd dir $path\autounattend.xml | New-IsoFile -Path $path\auto.iso -Media CDR -Title "Unattend" 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-VM -Name $name echo "When you press enter the Virtual Machine will be stopped and deleted" pause Stop-VM -Name $name -Force -TurnOff Remove-VM -Name $name -Force del $path\hyper-v.vhd del $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.


2 thoughts on “Testing unattended windows installations

  1. Thanks for this writeup – I am on Hyper-V (Server 2012 R2) and I see both media mounted (OS installer ISO on D: and the Unattend.iso on E:) – however it seems to hang on “Windows Setup” “Where do you want to install Windows?”. Bad autounattend.xml or is there something I’m missing?

    1. Hi Andy,
      If there are a list of partitions that were not there when you started then that part of your autounattend.xml is working. Perhaps you have not specified the drive to install to. Be aware that drive numbering starts from zero but partition numbering starts from 1. You need to have the /ImageInstall/OSImage/InstallTo/ key in Setup populated with the disk and partition that you want to install to. Another issue could be the destination partition is too small. You can refer to the following technet article to ensure you have all items required. Also you could try the sample to be sure there isn’t an issue somewhere else in your deployment.



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.