You’ve created yourself a shiny new virtual machine inside Hyper-V, quite possibly using a cool method of quick-deploying (or maybe Packer, or something else). You’ve already given your new baby a name inside Hyper-V Manager … but what about the Guest OS? Windows boots up and calls itself WIN-49NMA43RF, but let’s use Desired State Configuration and spruce things up a bit.
When building up a fleet of new VMs in Hyper-V for a lab project, you’ll need to connect to each VM, run through the Out-Of-Box-Experience since you’ve sysprepped your image/template, set the local Administrator password, log in, and rename the computer. This can be tedious. There are more enterprise-y ways to accomplish this when bootstrapping a VM, but here’s something quick and dirty I came up with.
The challenge with trying to rename the fresh new VM inside Hyper-V is, the host doesn’t know the name of the guest yet in order to connect to it and run commands to rename it; and the guest can’t ask for anything from the host. Well, it turns out Hyper-V actually writes some registry entries to VM guests, giving it some clue about its identity up above, at the host level. One of these registry values is the VM NAME inside Hyper-V Manager. Great, we can use that!
Get-ItemProperty –path “HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters”
Credit for that find goes to Hyper-V Program Manager Ben Armstrong’s Microsoft virtualization blog.
But instead of using Ben’s script, we can use Desired State Configuration inside the virtual machine to make sure the ComputerName always matches that value. Likewise, if the VMName at the host level changes, so too should the ComputerName inside the guest — that’s DSC magic.
Next problem to solve is how to implement a DSC configuration to run at first boot. Inspiration for this piece comes from the Windows Powershell Blog, which in their example, ensure IIS is installed on a webserver when it first boots.
The high-level steps are:
- Create a Desired State Configuration script that queries the registry for the VMName, then ensures it’s set as the ComputerName
- Use a command file to implement a Scheduled Task, which invokes the DSC script at each startup
- Create an Unattend.XML file for the first boot which runs the command file, and sets your local Admin password
- Load these scripts into your template VHDX
Step 1: DSC Powershell Script
Create a new PS1 file, mine is called FreshVM.ps1. This will go in C:\DSC inside your VM template VHDX.
Step 2: Command File for Scheduled Task
Create a new cmd file, mine is called RunDSC.cmd. This will go in C:\DSC alongside the FreshVM.ps1 file.
schtasks.exe /create /SC ONSTART /TN "\Microsoft\Windows\Desired State Configuration\DSCRestartBootTask" /RU System /F /TR "Powershell.exe -ExecutionPolicy RemoteSigned -File C:\DSC\FreshVM.ps1"
Step 3: Unattend.XML to create your Scheduled Task entry
Modify the file below with your path to RunDSC, and change the Admin password from Welcome1 to whatever you’d like. Save unattend.xml to the root of C:.
<?xml version='1.0' encoding='utf-8'?> <unattend xmlns="urn:schemas-microsoft-com:unattend"> <settings pass="specialize"> <component name="Microsoft-Windows-Deployment" 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"> <RunSynchronous> <RunSynchronousCommand> <Order>1</Order> <Path>%SystemDrive%\DSC\RunDSC.cmd</Path> </RunSynchronousCommand> </RunSynchronous> </component> </settings> <settings pass="oobeSystem"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> <OOBE> <HideEULAPage>true</HideEULAPage> <SkipMachineOOBE>true</SkipMachineOOBE> <SkipUserOOBE>true</SkipUserOOBE> <ProtectYourPC>3</ProtectYourPC> <NetworkLocation>Work</NetworkLocation> </OOBE> <UserAccounts> <AdministratorPassword> <Value>Welcome1</Value> <PlainText>true</PlainText> </AdministratorPassword> </UserAccounts> </component> </settings> </unattend>
Step 4: Packing It Up
If you’re working in a live VM, run sysprep and shut it down.
If you’re working in your VHDX template, unmount it and mark it read-only.
Now, deploy a new VM based on the changes you’ve just made.
On first boot, unattend.xml will run, setting your local Admin password.
Additionally, browse to Task Scheduler, then open this path in the tree:
\Microsoft\Windows\Desired State Configuration
You should see your new scheduled task show up. If not, reboot.
Now, to get your task to be triggered, reboot – the task is set to run on startup.
After another reboot, check your servername — it should match the VM Name!
Only caveat is you need to give your VM a name in Hyper-V which is free of spaces or special/illegal characters. Otherwise, your DSC script will error out.
Rolling this process into my Hyper-V VM Quick-Deploy method means I can hands-off deploy and name my virtual machines in one crack — pretty cool!