I tend to build many Windows VMs on XenServer and want a way to automate as much as possible.
I want to avoid using Sysprep. I’m getting a Windows 10 ISO from Microsoft every 6 months (semi-annual release). If I go with Sysprep, I have to manually create the VM, sysprep it, turn it into a template and finally create my VM. Plus, how many times can I sysprep before I run into license issues and sysprep count?
Seems like a lot of waste and trouble.
Instead, I want to automatically build a VM from a newly downloaded ISO file. The challenge is I need to have an unattend.xml file within the ISO. Let’s see how to accomplish that.
Before I begin, I need the following items:
- Unattend.xml for Windows 2016
- Unattend.xml for Windows 10
- ETFSBoot.com (from Windows ISO .\boot\etfsboot.com)
- OSCDIMG.exe (from Windows Assessment and Deployment Kit C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg)
- XenServer template for Windows 2016 (Blank template with CPU, RAM, Network and Storage allocated)
- XenServer template for Windows 10 (Blank template CPU, RAM, Network and Storage allocated)
- Windows 2016 ISO expanded to a folder
- Windows 10 ISO expanded to a folder
- XenServer PowerShell installed
The first part are all of my parameters
# Parameters # Name of virtual machines. Can be more than one, separated by comma $VMNames = @("Win10-718", "Win10-717") # PowerShell script to use after OS install completes. Need 1 entry per VMName $DeploymentScript = @("\\dc1\Automation\VMBuild\InstallVSITarget.ps1", "\\dc1\Automation\VMBuild\InstallVSITarget.ps1") # Folder to expanded ISO file. $ImagePath = @("\\media\iso\Win10-1803-Image","\\media\iso\Win10-1803-Image") # XenServer template with CPU, Memory, network and disk allocated. The disk is empty $SourceTemplateName = "XS Template - Windows 2016(Blank)" # Path to the log file $Logfile = "\\dc1\Automation\VMBuild\VMs" # Tools used to build an ISO file $BootFile = "\\dc1\Automation\Software\Oscdimg\etfsboot.com" $ISOTool = "\\dc1\Automation\Software\Oscdimg\oscdimg.exe" # Active Directory OU to place the VM during the build $OULocation = "OU=AutoBuildOU,DC=snpp,DC=local" # XenServer master, user and password $XenServerHost = "XS2.snpp.local" $UserName = "root" $Password = "Chuck Norris" # Path to the unattended XML file for the OS $UnattendTemplate = "\\dc1\Automation\VMBuild\AutoUnattendWin2016.xml" # Unattend.xml variables $AutoLogonPW = "Chuck Norris" $AutoLogonAcct = "AutoLogon" $DomainJoinAcct = "AutoLogon" $DomainJoinPW = "AutoLogon" $Domain = "SNPP" $FQDN = "SNPP.local" $LocalAdminPW = "Chuck Norris" $WinProductKey = "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"
I have 2 functions that helps with my log file
The first simply gets a data/timestamp for each log entry
function Get-TimeStamp { return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) }
The second is the log entry. It posts to the screen and to a text file (one for each VM being created)
Function Write-ScreenLog { Param ($textstring) write-host "$(get-timestamp) : $textstring" -foregroundcolor yellow Add-Content -Value "$(Get-timestamp): $textstring" -Path $Logfile\$VMName.txt }
Now, we create a VM, 1 loop for each defined VMName
$i=0 foreach ($VMName in $VMNames) { #Prepare Log file. If file does not exist, create. Else, if file exists from previous build, delete and create new file If((Test-Path $Logfile\$VMName.txt) -eq $false) { New-Item $Logfile\$VMName.txt -type file -force } else { Remove-item $Logfile\$VMName.txt New-Item $Logfile\$VMName.txt -type file -force } Write-ScreenLog "#############################" Write-ScreenLog "Creating new VM from ISO file" Write-ScreenLog "#############################" # Connect to XenServer Pool Master Write-ScreenLog "Connecting to XenServer host: $XenServerHost" $session = Connect-XenServer -Server $XenServerHost -UserName $UserName -Password $Password -NoWarnCertificates -SetDefaultSession -PassThru # Create XenServer VM from blank template Write-ScreenLog "Scheduling creation of vm '$VMName' from template '$SourceTemplateName'" # Get the source template $objSourceTemplate = Get-XenVM -Name $SourceTemplateName # Make a copy of the blank template Invoke-XenVM -NewName $VMName -VM $objSourceTemplate -XenAction Copy # Provision the copy into a VM Invoke-XenVM -XenAction Provision -Name $VMName # Copy template unattend.xml file to the expanded ISO path $ISOPath = $ImagePath[$i] Copy-Item $UnattendTemplate -Destination $ISOPath"\AutoUnattend.xml" #Customize unattend.xml $DefaultXML=Get-Content $ISOPath"\AutoUnattend.xml" $DefaultXML | Foreach-Object { $_ -replace '1DomainJoinAcct', $DomainJoinAcct ` -replace '1DomainJoinPW', $DomainJoinPW ` -replace '1AutoLogonAcct', $AutoLogonAcct ` -replace '1AutoLogonPW', $AutoLogonPW ` -replace '1OULocation', $OULocation ` -replace '1ComputerName', $VMName ` -replace '1Domain', $Domain ` -replace '1FQDN', $FQDN ` -replace '1LocalAdminPW', $LocalAdminPW ` -replace '1ProductKey', $WinProductKey ` -replace '1DeploymentScript', $DeploymentScript[$i] } | Set-Content $ISOPath"\AutoUnattend.xml" Write-ScreenLog "Deployment Script is $DeploymentScript[$i]" # Create Custom ISO file VM. This turns the folder that contains the ISO and unattend into a new ISO file Write-ScreenLog "Creating bootable ISO called \\media\iso\$VMName.ISO" $ISOArg = "-b$bootfile -u2 -h -m -l$VMName $ISOPath \\media\iso\$VMName.iso" Start-Process -FilePath $ISOTool -ArgumentList $ISOArg -PassThru -wait # Mount Customized OS ISO to VM Write-ScreenLog "Mounting customized ISO to $VMName" # Get the VM, select the virtual disks that are CD, attach the ISO get-xenvm -Name $VMName | select -ExpandProperty VBDs | Get-XenVBD | where {$_.type -eq "CD"} | Invoke-XenVBD -XenAction Insert -VDI (Get-XenVDI -Name $VMName".iso" | Select -ExpandProperty opaque_ref) #Start VM $VM = Get-XenVM -Name $VMName Write-ScreenLog "Scheduling power on of VM '$VMName'" Invoke-XenVM -VM $VM -XenAction Start -Async $i = $i + 1 } Write-ScreenLog "VM creation complete"
A few important things to point out.
I need to customize the Unattend.xml. I start with a template for Windows 10 and another one for Windows 2016. A few entries within the .XML file are variables used to customize the file from the PowerShell script. These include:
- 1DomainJoinPW
- 1AutoLogonAcct
- 1AutoLogonPW
- 1OULocation
- 1ComputerName
- 1DeploymentScript
- 1Domain
- 1FQDN
- 1LocalAdminPW
- 1ProductKey
The second part is to incorporate this customized Unattend.xml into an bootable ISO file. Using ETFSBoot and OSCDIMG, I take my folder containing the expanded ISO and unattend.xml and create a customized, bootable ISO file, which I later attach to the VM. The ISO has the same name as the VM because we might have multiple VMs building simultaneously.
When Windows 10 1803 released, I was able to grab the ISO and immediately create a custom VM.
Nice work!
LikeLike
Hi Dan
Fab little article and just what I was looking for although I’ve never used PS with XS before to deploy VM’s onto XS. Is this faster at deploying a VM than from say a XenServer Template ?
On a related notes, is there a XD/XA infrastructure deployment template or script for XenServer that would stand up, AD, Storefront, DDC’s and even the VDA like an AWS cloud transformation template ?
Thanks
H
LikeLike
XS template works as well. That is how I originally started. My problem is that as this is a lab env, my OS will time out after so many months, which requires me to keep recreating templates. Plus, when new versions of Win10 come out (every 6 months), I don’t want to have to create new templates.
As for whole deployment scripts, not sure. I know Trond Eirik Haavarstein from https://xenappblog.com/ has an automation framework, but not what it does.
LikeLike
Hey Dan, What settings did you have in your unattended file for 1803 to skip the OOBE. Image manager says the settings are deprecated and for sure thats what I’m seeing. Would love to know how you got around this, its driving me nuts.
LikeLike
I’ve got the Win10 and Win2016 unattended posted. Look in the Powershell menu item. Let me know if it still doesn’t work.
LikeLike
Hi Dan, and you’ve got this working for 1803? I’ll download and spin up some VMS using your templates exactly. Thanks coming back to me.
LikeLike
Yeah. Actually just built a Win10 1803 yesterday with this.
LikeLike
Strange, I’m getting Cortana popping up and asking me questions after the install is complete. Domain join works well and is fine. It’s just the oobe question I want to get rid of.
LikeLiked by 1 person
What flavor of Win10 are you using? Mine is Enterprise.
LikeLike
Found my issue Dan, a mismatch in ISO vs Unattend. Thanks for coming back to me and for the script, its kickstarted my latest project nicely. Be good sir!
LikeLike