‘Mass’ sysprep your Windows VMs for Nutanix AHV

WindowsAfter reading this excellent blogpost from Andrew Nelson (Distributed Systems Specialist at Nutanix) on Acropolis Image and Cloning Primer for Automation and combining that with this blogpost from Raghu Nandan (Director of Product Management) on Setting up Citrix XA/XD with an Acropolis Hypervisor cluster I figured we were missing one vendor on this list.. Microsoft Windows Server/Client OSs.

Although the blogpost from Raghu offers a solid way to deploy your Windows based VM(s) on Nutanix AHV I’ve been working on a way to do so without the need of client components on the VM side of things.

One way to do so is utilising Windows native PowerShell which is pretty straightforward except for one little caveat: Remote PowerShell does not play nicely with non-domain joined machines as there’s no easy way to authenticate. It could work with SSL certificates etc but that’s adding more complexity as it is so I went for a solution that could be executed with PsExec which is a light-weight telnet-replacement that lets you execute processes on other systems, complete with full interactivity for console applications, without having to manually install client software. PsExec’s most powerful uses include launching interactive command-prompts on remote systems and remote-enabling tools like IpConfig that otherwise do not have the ability to show information about remote systems.

The good thing about working with sysprep is that it will offer a way to execute it unattended wit an unattended.xml. You can describe your parameters in this XML file and sysprep.exe will parse them into the right commands. A detailed explanation of how this would work can be found on the TechNet forums, there’s an easy way to validate your unattended.xml file to using the Windows System Image Manager (Windows SIM).

With that being said, I’ve came up with the following PowerShell script to do a remote execution of a sysprep for your Windows VM:



As you can see it generates the unattended.xml on the local system so the remote execution of sysprep can find the XML file. One thing that I like about this approach is that it’s more flexible in terms of your VM naming scheme, OU placement and settings as you’re able to dynamically change/adjust the settings per VM. This script was tested on Windows 2008R2 and Windows 7 and  comes ‘as-is’.

Pro-tip: If you think it’s too much work to launch SIM you could always try to use of the online generators for your unattended.xml which can be found here: http://windowsafg.no-ip.org/, please note that there are multiple options for your XML file depending on your Windows version so please choose the right OS before creating your xml file.

The following two tabs change content below.

Kees Baggerman

Kees Baggerman is a Staff Solutions Architect for End User Computing at Nutanix. Kees has driven numerous Microsoft and Citrix, and RES infrastructures functional/technical designs, migrations, implementations engagements over the years.


  1. Remko says:

    Hi Kees,

    You already have the XML template in a string so there’s no need to save it to disk and then load it as xml. It’s much easier to simply cast it as xml:

    Source code    
    1. $xml = [xml]$template

    As for setting the properties in XML, I don’t like hardcoded arrays since it makes the code more difficult to read (and I do read a script before executing it). It’s also more error prone as the order might change in the future.

    So instead of this:
    $xml.unattend.settings[0].component[1].UserData.FullName = $RegisteredName

    I recommend this:

    Source code    
    1. $ns = New-Object Xml.XmlNamespaceManager($xml.NameTable)
    2. $ns.AddNamespace("unattend", $xml.DocumentElement.NamespaceURI)
    4. $msWinSetup = $xml.SelectSingleNode("//unattend:settings[@pass='windowsPE']/unattend:component[@name='Microsoft-Windows-Setup']", $ns)
    5. $msWinSetup.UserData.FullName = $RegisteredName
    6. $msWinSetup.UserData.Organization = $Organization
    8. $msWinShellSetup = $xml.SelectSingleNode("//unattend:settings[@pass='specialize']/unattend:component[@name='Microsoft-Windows-Shell-Setup']", $ns)
    9. $msWinShellSetup.ComputerName = $ComputerName
    11. $msWinUnattendJoin = $xml.SelectSingleNode("//unattend:settings[@pass='specialize']/unattend:component[@name='Microsoft-Windows-UnattendedJoin']", $ns)
    12. $msWinUnattendJoin.identification.JoinDomain = $DomainName
    13. $msWinUnattendJoin.identification.credentials.UserName = $DomainUser
    14. $msWinUnattendJoin.identification.credentials.Password = ConvertTo-PlainText $DomainPwd
    15. $msWinUnattendJoin.identification.credentials.Domain = $DomainName
  2. […] ‘Mass’ sysprep your Windows VMs for Nutanix AHV […]

Leave a Reply