HOWTO: Automate Deployment of VMware Workstation VMs

This HOWTO describes the fastest way I’ve figured out thus far to deploy net-new Windows 2012 VMs using VMware Workstation for a Lab environment.  The first thing we need to do is build our "golden master" VM.  For our purposes, we will be using the Windows 2012 R2 180 Trial ISO which is freely available to download from Microsoft.  (Note, this script assumes you have already created a domain controller.  If you have not, then the domain joining functionality of this script will fail obviously.  I’ll likely create a new post on how to automate the deployment of that too at some point.)

  • Once you have the ISO, build a new VM and install Windows 2012 on the VM as you normally would
  • Run all windows updates on the VM to make it as current as possible
  • Make any other configuration changes you’d like.  My changes included:
    • Install Dot Net since many things will require it anyway
    • Set Keyboard refresh rate
    • Allow ICMP through the firewall
    • Disable IE Security Configuration
    • Enable Hidden files and file extensions
    • Add Notepad2 to the right click context menu
    • Copy my standalone tools folder to c:\bin
    • And more…

  • Once you’re satisfied with the VM, copy and paste the following XML into c:\windows\system32\sysprep\Autounattend.xml
<?xml version="1.0" encoding="utf-8"?>
 <unattend xmlns="urn:schemas-microsoft-com:unattend">
 <settings pass="oobeSystem">
     <component name="Microsoft-Windows-International-Core" 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">
         <InputLocale>en-US</InputLocale>
         <SystemLocale>en-US</SystemLocale>
         <UILanguage>en-US</UILanguage>
         <UILanguageFallback>en-US</UILanguageFallback>
         <UserLocale>en-US</UserLocale>
     </component>
     <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">
         <OOBE>
             <HideEULAPage>true</HideEULAPage>
             <NetworkLocation>Work</NetworkLocation>
             <ProtectYourPC>3</ProtectYourPC>
         </OOBE>
         <UserAccounts>
           <AdministratorPassword>
             <Value>{INSERTPASSWORDHERE}</Value>
           </AdministratorPassword>
         </UserAccounts>
         <TimeZone>Mountain Standard Time</TimeZone>
     </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">
         <CopyProfile>true</CopyProfile>
     </component>
 </settings>
 </unattend>
  • These settings will take care of the following for you:
    • Skip the language and region settings screens that normally occur after a sysprep
    • Skips the EULA screen that normally appears
    • Sets the default local administrator password (must be changed above)
    • Sets the default time zone
    • Copies over the existing profile settings so that UI changes made prior to the sysprep are carried over
  • Next, create a file called C:\users\administrator\desktop\computersetup.ps1 and place the following inside it

# Asks the user for a computer name and IP address and sets those on the current machine, and optionally joins to the domain
# VM; New Machine; IP Address; Computername; Hostname; Domain Join;

# Force execution of code to run as administrator (requires prompting the user to run as administrator)
param([switch]$Elevated)

function Test-Admin {
  $currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
  $currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

if ((Test-Admin) -eq $false)  {
    if ($elevated) 
    {
        # tried to elevate, did not work, aborting
    } 
    else {
        Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -noexit -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition))
}

exit
}

$DefaultGateway = "10.0.0.1"
$DNSServer = "10.0.0.11"
$domain = "yourdomain.here"
$password = "{INSERTPASSWORDHERE}" | ConvertTo-SecureString -asPlainText -Force
$username = "$domain\{INSERTUSERNAMEHERE}" 

$ComputerName = Read-Host "What computer name? (Blank to skip)"

if($ComputerName -ne "") { Rename-Computer $ComputerName }

$IPAddress = Read-Host "What IP Address? (Blank to skip)"

if($IPAddress -ne "")
{
  # Cannot edit existing IP configuration with Powershell -- must remove and then add new
  # This section removes the existing IP configuration on the default network interface
  Remove-NetIPAddress -InterfaceAlias Ethernet0 -confirm:$false -ErrorAction SilentlyContinue
  remove-netroute -interfaceAlias Ethernet0 -confirm:$false -ErrorAction SilentlyContinue

  #Add New IP information
  New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress $IPAddress -PrefixLength "24" -DefaultGateway  $DefaultGateway
  Set-DnsClientServerAddress -InterfaceAlias Ethernet0 -ServerAddresses $DNSServer
}
Write-Host "Waiting for network configuration to update..."
sleep 4
$DomainJoin = Read-Host "Join the $domain domain? (y/n)"

if($DomainJoin -eq "y") 
{ 
  $credential = New-Object System.Management.Automation.PSCredential($username,$password)
  Add-Computer -DomainName $domain –NewName $ComputerName -Credential $credential
}

$RebootNow = Read-Host "Reboot computer? (y/n)"

if($RebootNow -eq "y") { Restart-Computer }

Once you've logged in, double click on this file to set the computer name, IP address and join the computer to the domain.  It will reboot automatically upon completion
  • Lastly, run the following command to sysprep the VM:

c:\windows\system32\sysprep\sysprep /generalize /oobe /shutdown /unattend:Autounattend.xml

  • With the VM powered off, right click on it and choose Manage / Clone and create a Linked Clone
  • Power up the clone.  If all goes according to plan, with out you doing anything, the system should automatically boot to the login screen.  Login with the local admin password and double click on the computersetup script on the desktop
  • Provide the desired computer name, IP address and press "y" to join the computer to the domain

Congratulations, after this final reboot, the server should now be ready for you to use with all the latest updates installed, all of your custom software, tools and other configurations already present!

It’s also worth noting that the 180 day trial countdown that appears in the bottom right corner of the screen appears to reset on each clone and therefore this template should in theory last indefinitely.

Leave a Reply

Your email address will not be published.

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