If you follow the differencing VHD approach from my previous posts (this & this) you’ll notice the boot process starts off by getting the devices ready, does a reboot or two, and then you are taken to a prompt to set the Administrator password.
Do that and you are set. There’s no other prompting in terms of selecting the image, partitioning etc (because we have bypassed all these stages of the install process).
Would be good if I could somehow specify the admin password and the server name automatically – say via an answer file. That’ll take care of the two basic stuff I do always any way. My admin password is common for all the machines, and the server name is same as the VM name, so these can be figured out automatically to use with an answer file.
The proper way to create an answer file is too much work and not really needed here. So I Googled for answer files, found one, removed most of it as it was unnecessary, and the result is something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="utf-8"?> <unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:ms="urn:schemas-microsoft-com:asm.v3" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> <settings pass="oobeSystem"> <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"> <UserAccounts> <AdministratorPassword> <Value>P@ssw0rd</Value> <PlainText>true</PlainText> </AdministratorPassword> </UserAccounts> </component> </settings> <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>--REPLACE--</ComputerName> <RegisteredOwner>Rakhesh Sasidharan</RegisteredOwner> <RegisteredOrganization>rakhesh.com</RegisteredOrganization> <TimeZone>Arabian Standard Time</TimeZone> </component> </settings> </unattend> |
If you replace the text marked with –REPLACE– with the computer name, and save this to the c:\ of a newly created VM, the password and computer name will be automatically set for you!
So here’s what I do in addition to the steps before.
Create the differencing VHD as usual
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
PS D:\NoBackup> New-VHD -Differencing -Path '.\Hyper-V\Virtual Hard Disks\WINDC01.VHDX' -ParentPath '.\Hyper-V\Virtual Hard Disks\2012r2-std-core.vhdx' ComputerName : TINTIN Path : D:\NoBackup\Hyper-V\Virtual Hard Disks\WINDC01.VHDX VhdFormat : VHDX VhdType : Differencing FileSize : 4194304 Size : 26843545600 MinimumSize : 26842513920 LogicalSectorSize : 512 PhysicalSectorSize : 4096 BlockSize : 2097152 ParentPath : D:\NoBackup\Hyper-V\Virtual Hard Disks\2012r2-std-core.vhdx DiskIdentifier : a5548da4-bbd1-4259-b97c-b8cf164dc5b4 FragmentationPercentage : Alignment : 1 Attached : False DiskNumber : Key : IsDeleted : False Number : |
Save the XML file above as “Unattend.xml”. Doesn’t matter where you save it as long as you, I’ll assume it’s in my current directory. If it is saved anyplace else replace the path accordingly in the second cmdlet below.
Mount the VHD, copy the answer file over replacing the machine name with what you want, dismount the VHD. Finito!
1 2 3 |
PS D:\NoBackup> $VHD = (Mount-VHD '.\Hyper-V\Virtual Hard Disks\WINDC01.VHDX' -Passthru | Get-Disk | Get-Partition | ?{$_.Type -eq "Basic" }).DriveLetter PS D:\NoBackup> $(Get-Content .\Unattend.xml) -replace "--REPLACE--","WINDC01" | Out-File "${VHD}:\\Unattend.xml" -Encoding ASCII PS D:\NoBackup> disMount-VHD '.\Hyper-V\Virtual Hard Disks\WINDC01.VHDX' |
That’s it really.
A different way to manipulate the XML file
I used the -replace
operator above to make changes to the XML file. But I can do things differently too as PowerShell understands XML natively.
1 2 3 |
PS D:\NoBackup> [xml]$Unattend = Get-Content .\Unattend.xml # Read the XML file into a variable PS D:\NoBackup> ($Unattend.unattend.settings | ?{ $_.pass -eq "specialize" }).component.ComputerName = "WINDC01" PS D:\NoBackup> $Unattend.Save("${VHD}:\\Unattend.xml") |
Three cmdlets instead of one, but this might feel “neater”.