beawolf - Fotolia

Tip

With Packer, VM template creation is easy

Templates are the quickest, easiest way to deploy VMs in vSphere. You can use a free tool such as Packer and a builder such as vmware-iso to automate the creation of VM templates.

Templates make the process of deploying VMs in vSphere faster, easier and more efficient than manually deploying VMs. Packer is a free tool that can help you automate vSphere template creation and management, and you can use the vsphere-iso plugin to integrate Packer, vCenter and Windows.

Templates represent a static starting point for a VM, and you can configure different settings -- such as the IP address, Active Directory domain and host name -- to make them unique. You can then deploy VMs from templates with command-line tools, such as PowerCLI.

Historically, you had to manually create VM templates in vSphere. To manually create a template, you must mount an ISO file on the VM, install Windows and make any changes to the template through the GUI. Instead, Packer automates the image building process from the OS installation through saving a VM as a template.

Packer builders

Packer features multiple builders, but many such builders are optimized for VMware Fusion, Workstation and Workstation Player. For organizations with a vSphere environment, it might seem silly to use a workstation to build a production template.

The vmware-iso builder supports using a remote ESXi server for building a template. However, this builder communicates directly with the ESXi host via secure shell, which means you can't simply use the host with the most available resources. It also means, if you retire a host, you must make changes in your configuration file to point to a new host.

You can use a Packer plugin called vsphere-iso with the vmware-iso builder to connect to a vCenter environment and build on any host in a cluster.

Packer JSON

When you use Packer to make a VM template with Windows and vSphere, you work with two main file types: the JSON file -- which makes up the template -- and the autounattend file that automates the Windows installation on a VM. When Packer mounts the scripts specified in your floppy files, you should find the autounattend.xml file among them.

{
    "builders": [
        {
        "type": "vsphere-iso",
        "boot_wait": "5m",
        "vcenter_server": "vcenter",
        "datacenter": "mydatacenter",
        "insecure_connection": "true",
        "username": "[email protected]",
        "password": "#P@ssword",
        "cluster": "Dev Cluster",
        "floppy_files": [
            "./answer_files/2019/Autounattend.xml",
            "./scripts/disable-screensaver.ps1",
            "./scripts/enable-winrm.ps1",
            "./scripts/microsoft-updates.bat",
            "./scripts/unattend.xml",
            "./scripts/sysprep.bat",
            "./scripts/win-updates.ps1",
            "./scripts/chocoinstall.ps1",
            "./scripts/installvmtools.ps1"
          ],
        "vm_name":  "WindowsServer2019",
        "communicator": "winrm",
        "winrm_username": "admin",
        "winrm_password": "P@ssword5",
        "convert_to_template": "true",
        "cpus": "2",
        "ram": "4096",
        "network": "VM Network",
        "disk_controller_type": "lsilogic-sas",
        "network_card": "e1000e",
        "guest_os_type": "windows9Server64Guest",
        "datastore": "mydatastore",
        "disk_size": "70000",
        "shutdown_command": "a:/sysprep.bat",
        "iso_paths": "[mydatastore]
INSTALL_MEDIA/SW_DVD9_Win_Server_STD_CORE_2019_1809.1_64Bit_English_DC_STD_MLF_X22-02970.ISO"
        }
    ],
    "provisioners": [
        {
            "restart_timeout": "5m",
            "type": "windows-restart"
        },
        {
          "scripts": [
            "./scripts/enable-rdp.bat"
          ],
          "type": "windows-shell"
        },
        {
          "restart_timeout": "5m",
          "type": "windows-restart"
        }
      ]
}

"type": "vsphere-iso" represents the Packer builder type provided by the JetBrains plugin. Certain settings -- such as "vcenter_server" -- are only available with that plugin.

The "convert_to_template": "true" setting automatically converts a VM to a template at the end of a build without a post processor.

"network": "VM Network" defines the network that you build your VM on. You might not require network connectivity during the build process, but if you intend to download and install software remotely, you'll require a network later.

"iso_paths": "[mydatastore] INSTALL_MEDIA/SW_DVD9_Win_Server_STD_CORE_2019_1809.1_64Bit_English_DC_STD_MLF_X22-02970.ISO" sets the location of your installation media -- in this case, Windows Server 2019. The vsphere-iso plugin requires media on a datastore connected to your vSphere environment.

Use "shutdown_command": "a:/sysprep.bat" to specify that Packer run a BAT file with the sysprep command in it. This should be the final task in most Windows builds.

Autounattend file

The autounattend file automates much of the Windows setup.

You can modify the autounattend file. At the end of the FirstLogonCommand pass, you can add commands that run at the first logon after Windows is installed. For example, you can automate the Chocolatey installation and then the VMware Tools (VMtools) installation using Chocolatey.

<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\chocoinstall.ps1</CommandLine>
<Description>Install Choco</Description>
<Order>101</Order>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\installvmtools.ps1</CommandLine>
<Description>Install VMtools</Description>
<Order>102</Order>
</SynchronousCommand>

Add a chocoinstall.ps1 script to install Chocolatey.

Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

The installvmtools.ps1 file includes a Chocolatey install command.

C:\ProgramData\chocolatey\choco.exe install vmware-tools -y

When you use the vsphere-iso plugin, make sure you have VMtools installed. VMtools populates the VM's IP address into vCenter, and the builder waits for that IP address before it continues to the provisioners section of the JSON file.

Running the Packer build

Once your scripts, JSON file and autounattend file are ready, you can begin your Packer VM template build.

C:\packer> packer build -force '.\windows_2019_VM.json'
vsphere-iso output will be in this color.

==> vsphere-iso: Creating VM...
==> vsphere-iso: Customizing hardware...
==> vsphere-iso: Mount ISO images...
==> vsphere-iso: Creating floppy disk...
    vsphere-iso: Copying files flatly from floppy_files
    vsphere-iso: Copying file: ./answer_files/2019/Autounattend.xml
    vsphere-iso: Copying file: ./scripts/disable-screensaver.ps1
    vsphere-iso: Copying file: ./scripts/disable-winrm.ps1
    vsphere-iso: Copying file: ./scripts/enable-winrm.ps1
    vsphere-iso: Copying file: ./scripts/microsoft-updates.bat
    vsphere-iso: Copying file: ./scripts/unattend.xml
    vsphere-iso: Copying file: ./scripts/sysprep.bat
    vsphere-iso: Copying file: ./scripts/win-updates.ps1
    vsphere-iso: Copying file: ./scripts/chocoinstall.ps1
    vsphere-iso: Copying file: ./scripts/installvmtools.ps1
    vsphere-iso: Done copying files from floppy_files
    vsphere-iso: Collecting paths from floppy_dirs
    vsphere-iso: Resulting paths from floppy_dirs : []
    vsphere-iso: Done copying paths from floppy_dirs
==> vsphere-iso: Uploading created floppy image
==> vsphere-iso: Adding generated Floppy...
==> vsphere-iso: Set boot order temporary...
==> vsphere-iso: Power on VM...
==> vsphere-iso: Waiting for IP...
==> vsphere-iso: IP address: 172.16.62.112
==> vsphere-iso: Using winrm communicator to connect: 172.16.62.112
==> vsphere-iso: Waiting for WinRM to become available...
  vsphere-iso: #< CLIXML
  vsphere-iso: WinRM connected.
  vsphere-iso: <Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>

==> vsphere-iso: Connected to WinRM!
==> vsphere-iso: Restarting Machine
==> vsphere-iso: Waiting for machine to restart...
   vsphere-iso: WindowsServer2019 restarted.
==> vsphere-iso: #< CLIXML
==> vsphere-iso: <Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
==> vsphere-iso: Machine successfully restarted, moving on
==> vsphere-iso: Provisioning with windows-shell...
==> vsphere-iso: Provisioning with shell script: ./scripts/enable-rdp.bat
    vsphere-iso:
    vsphere-iso: C:\Users\admin>netsh advfirewall firewall add rule name="Open Port 3389" dir=in action=allow protocol=TCP localport=3389
    vsphere-iso: Ok.
    vsphere-iso:
    vsphere-iso:
    vsphere-iso: C:\Users\admin>reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
    vsphere-iso: The operation completed successfully.
==> vsphere-iso: Restarting Machine
==> vsphere-iso: Waiting for machine to restart...
==> vsphere-iso: A system shutdown is in progress.(1115)
  vsphere-iso: WindowsServe2019 restarted.
==> vsphere-iso: #< CLIXML
==> vsphere-iso: <Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
==> vsphere-iso: Machine successfully restarted, moving on
==> vsphere-iso: Executing shutdown command...
==> vsphere-iso: Deleting Floppy drives...
==> vsphere-iso: Deleting Floppy image...
==> vsphere-iso: Eject CD-ROM drives...
==> vsphere-iso: Convert VM into template...
==> vsphere-iso: Clear boot order...
Build 'vsphere-iso' finished.

==> Builds finished. The artifacts of successful builds are

You must open Windows Remote Management (WinRM) on your VM to run any provisioners in Packer. The enable-winrm.ps1 script runs in the autounattend file.

$profile = Get-NetConnectionProfile
Set-NetConnectionProfile -Name $profile.Name -NetworkCategory Private
Enable-PSRemoting –Force
winrm quickconfig –q
winrm quickconfig -transport:http
winrm set winrm/config '@{MaxTimeoutms="1800000"}'
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="800"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/client/auth '@{Basic="true"}'
winrm set winrm/config/listener?Address=*+Transport=HTTP '@{Port="5985"}'
netsh advfirewall firewall set rule group="Windows Remote Administration" new enable=yes
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=allow
Set-Service winrm -startuptype "auto"
Restart-Service winrm

WinRM communicates with Packer and enables Packer to run scripts. When you deploy a new VM from a template, make sure you secure WinRM through your configuration management system to keep unencrypted traffic out of a production server.

Once complete, Packer converts your VM to a template that you can view in PowerCLI.

Dig Deeper on VMware ESXi, vSphere and vCenter