Getting Started With Packer to Create vSphere Templates – Part 2 - Answer Files and Scripts

Posted by Stephan McTighe on 22 Jun 2021

Welcome to part 2 of my Getting Started with Packer series, if you missed part 1, you can find it here. In part 2, we will take a look through an important part of creating your vSphere templates; Answer Files and scripts.

Firstly, we will be looking at a couple of example scripts that can be used to configure your operating system before its turned into your template. We will then move on to answer files that allow an automated, non user prompting installation of your operating system. These answer files provide configuration details during the operating system installation.

Let’s get started!

Scripts, Drivers and Media

These can be referenced either during the installation of the operating system via the answer file, like VMTools is during the Windows example below. They can also be run by a Provisioner via PowerShell or Shell, after the operating system install has completed. If media is required during the installation of the operating system, such as disk controller drivers or VMware Tools, they need to be made available to the operating system during installation. This can be achieved in multiple ways, Floppy disks, CD_rom, via a HTTP server or a combination. Either way you are going to need them available, more on how to make them available later in the series, but for now lets look at a couple of examples.

Scripts

Disabling TLS (Windows)

Here is an example script for disabling TLS 1.0 &1.1 on Windows using a PowerShell script. This could be run during the installation via the answer file, or via the PowerShell Provisioner. If running during the installation of the OS, this must be mounted as media during the installation. If it’s being run via the Provisioner, this can be referencing directly from the working directory of the machine you are running Packer from.

 1#Disable TLS 1.0
 2new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" -Name "TLS 1.0"
 3new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0" -Name "Server"
 4new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0" -Name "Client"
 5new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client" -Name "Enabled" -Value 0
 6new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client" -Name "DisabledByDefault" -Value 1
 7new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" -Name "Enabled" -Value 0
 8new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" -Name "DisabledByDefault" -Value 1
 9
10#Disable TLS 1.1
11new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" -Name "TLS 1.1"
12new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1" -Name "Server"
13new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1" -Name "Client"
14new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" -Name "Enabled" -Value 0
15new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" -Name "DisabledByDefault" -Value 1
16new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" -Name "Enabled" -Value 0
17new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" -Name "DisabledByDefault" -Value 1

This is a simple script to create the required registry entries to disable TLS versions 1.0 &1.1.

Updating Installed Packages (Linux)

Now let’s look at a CentOS example. Here is an example Shell script for updating all installed packages, that again can be ran via the answer file (kickstart.cfg) or via the Shell Provisioner.

1# Update existing packages
2sudo yum update -y

Drivers

Depending on the type of disk controller you plan on using for your templates and subsequent virtual machines, you may need to make drivers available during the operating system installation. An example of this are drivers for ParaVirtual SCSI (PVSCSI) disk controllers. These drivers aren’t available in during a Windows installation by default and need to be provided.

These can be mounted via floppy or another method. They just need to be available during the operating system installation. I stick to floppy currently as I don’t have to do anything other than reference the folder containing the drivers, along with my answer file and required scripts:

1floppy_files         = var.config_files

This is the floppy_files config line referencing the variable ‘config_files’. That variable references the path and file name of each file I wish to make available to the VM.

Here is detail of that variable as an example. It is referencing files in two directories, config and scripts, within my template parent directory.

1config_files            = ["config/autounattend.xml","scripts/pvscsi","scripts/install-vm-tools.cmd","scripts/enable-winrm.ps1"]

If you don’t provide drivers where needed, your operating system installation will fail.

Media

Depending on what you intend to install on your templates, you will need to make any install media or install scripts available. Like above, you can either mount any media to the VM using the floppy_files option and run the installs from the answer file, or via the Provisioner referencing your local working directory.

Examples of media or installations could be security products such as Antivirus or Data Loss Preventions agents, Management/Monitoring agents such as System Center Configuration Manager (SCCM) or System Center Operations Manager (SCOM).

There is no right or wrong answer as to what you should include in your templates, this is something you need to decide based upon your needs and environment. Although I would say, keep them as light as possible and use the right tool for the job. Consider using configuration management tools when its the right time too!

Answer Files

As we touched upon above, answer files are used to provide configuration details during the operating system install. In this blog, we will take a look at two types of answer files; A windows autounattended.xml & a CentOS kickstart.cfg.

Lets begin with the Windows answer file. You can create a Windows answer file using the Windows System Image Manager (Windows SIM) which you can find more information on here.

There are multiple sections within this file from the locale settings, disk partition configurations, the edition of Windows and even a section to stop the administrator account from expiring.

Here is a cut down example of a Windows answer file, you can find a complete example on my GitHub:

 1<?xml version="1.0" encoding="utf-8"?>
 2<unattend xmlns="urn:schemas-microsoft-com:unattend">
 3    <settings pass="windowsPE">
 4        <component name="Microsoft-Windows-International-Core-WinPE" 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">
 5            <SetupUILanguage>
 6                <UILanguage>en-US</UILanguage>
 7            </SetupUILanguage>
 8            <InputLocale>en-GB</InputLocale>
 9            <SystemLocale>en-GB</SystemLocale>
10            <UILanguage>en-US</UILanguage>
11            <UserLocale>en-US</UserLocale>
12        </component>
13...
14        <component name="Microsoft-Windows-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">
15            <DiskConfiguration>
16                <Disk wcm:action="add">
17                    <CreatePartitions>
18                        <CreatePartition wcm:action="add">
19                            <Order>1</Order>
20                            <Size>350</Size>
21                            <Type>Primary</Type>
22                        </CreatePartition>
23                        <CreatePartition wcm:action="add">
24                            <Order>2</Order>
25                            <Size>100</Size>
26                            <Type>EFI</Type>
27                        </CreatePartition>
28...
29                </Disk>
30                <WillShowUI>OnError</WillShowUI>
31            </DiskConfiguration>
32...
33            <UserData>
34                <AcceptEula>true</AcceptEula>
35            </UserData>
36        </component>
37    </settings>
38    <settings pass="specialize">
39...
40        <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">
41            <RunSynchronous>
42                <RunSynchronousCommand wcm:action="add">
43                    <Order>1</Order>
44                    <Description>Disable Network Discovery</Description>
45                    <Path>cmd.exe /c a:\disable-network-discovery.cmd</Path>
46                </RunSynchronousCommand>
47            </RunSynchronous>
48        </component>
49    </settings>
50    <settings pass="oobeSystem">
51        <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">
52            <AutoLogon>
53                <Password>
54                    <Value>VgBNAHcAYQByAGUAMQAyADMAIQA=</Value>
55                    <PlainText>false</PlainText>
56                </Password>
57                <LogonCount>2</LogonCount>
58                <Username>Administrator</Username>
59                <Enabled>true</Enabled>
60            </AutoLogon>
61                    <FirstLogonCommands>
62...
63                <SynchronousCommand wcm:action="add">
64                    <CommandLine>cmd.exe /c wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE</CommandLine>
65                    <Order>10</Order>
66                    <Description>Disable password expiration for Administrator user</Description>
67                </SynchronousCommand>
68                <SynchronousCommand wcm:action="add">
69                    <CommandLine>cmd.exe /c a:\install-vm-tools.cmd</CommandLine>
70                    <Order>11</Order>
71                    <Description>Install VMware Tools</Description>
72                </SynchronousCommand>
73                <SynchronousCommand wcm:action="add">
74                    <CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\enable-winrm.ps1</CommandLine>
75                    <Description>Enable WinRM</Description>
76                    <Order>99</Order>
77                </SynchronousCommand>
78            </FirstLogonCommands>
79...
80            <UserAccounts>
81                <AdministratorPassword>
82                    <Value>VgBNAHcAYQByAGUAMQAyADMAIQA=</Value>
83                    <PlainText>false</PlainText>
84                </AdministratorPassword>
85            </UserAccounts>
86        </component>
87    </settings>
88    <cpi:offlineImage cpi:source="wim:c:/wim/install.wim#Windows Server 2019 SERVERSTANDARDCORE" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
89</unattend>

Key parts of this file are the installation of VMTools and the enabling of WinRM:

 1<SynchronousCommand wcm:action="add">
 2                    <CommandLine>cmd.exe /c a:\install-vm-tools.cmd</CommandLine>
 3                    <Order>11</Order>
 4                    <Description>Install VMware Tools</Description>
 5                </SynchronousCommand>
 6
 7<SynchronousCommand wcm:action="add">
 8                    <CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\enable-winrm.ps1</CommandLine>
 9                    <Description>Enable WinRM</Description>
10                    <Order>99</Order>
11                </SynchronousCommand>

VMTools is important to make sure that the correct drivers are installed, ensuring you can get a network connection etc, and you need WinRM and the appropriate firewall rules to be enabled, to allow Packer to continue any post OS install configurations to take place via PowerShell Provisioner block. If WinRM isn’t enabled and working, you wont be able to complete any post install configuration actions!

You will notice both these actions are achieved by running a script from a floppy drive. A:. As touched upon earlier, these can be made available to the virtual machine as floppy disks (other options available) as it is built and subsequently removed when the build is complete.

One other setting to mention, the Administrator password in encrypted, you don’t want to be leaving this in plain text!

1<Password>
2                    <Value>VgBNAHcAYQByAGUAMQAyADMAIQA=</Value>
3                    <PlainText>flase</PlainText>
4                </Password>

Lets now take a look at a Linux Kickstart.cfg file, again cut down but a complete annotated example can be found here:

 1**install**
 2**cdrom**
 3**lang en_GB**
 4**keyboard --vckeymap=uk --xlayouts='gb'**
 5**network --onboot yes --bootproto=dhcp --activate**
 6**rootpw --iscrypted $1$JlSBrxl.$ksXaF7TIE.70iV12//V4R0**
 7**firewall --disabled**
 8**authconfig –enableshadow –enablemd5**
 9**selinux --permissive**
10**timezone --utc Europe/london --isUtc**
11**bootloader --location=mbr --append="crashkernel=auto rhgb quiet" --password=$1$JlSBrxl.$ksXaF7TIE.70iV12//V4R0
12autopart --type=lvm**
13**clearpart --linux --initlabel**
14**firstboot --disabled
15eula --agreed
16services --enabled=NetworkManager,sshd**
17**user --name=linux_user --iscrypted --password=$1$JlSBrxl.$ksXaF7TIE.70iV12//V4R0 --groups=wheel**
18**%packages --ignoremissing --excludedocs
19@core
20sudo
21net-tools
22ntp
23ntpdate
24vim
25wget
26curl
27git
28yum-utils
29perl**
30**-aic94xx-firmware
31-alsa-*
32-btrfs-progs*
33-centos-logos
34-dracut-config-rescue
35-dracut-network
36-microcode_ctl
37-NetworkManager*
38-ivtv-firmware
39-iwl*firmware
40-plymouth***
41%end 
42%post
43**chkconfig ntpd on
44chkconfig sshd on
45chkconfig ypbind on
46chkconfig iptables off
47chkconfig ip6tables off
48chkconfig yum-updatesd off
49chkconfig haldaemon off
50chkconfig mcstrans off
51chkconfig sysstat off**
52**echo "linux_user        ALL=(ALL)       NOPASSWD: ALL" >> /etc/sudoers.d/linux_user
53sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers**
54%end
55**reboot --eject**

Although this may look completely different it is still doing similar things as a Windows answerfile.

We are still detailing locale settings and encrypted passwords:

1rootpw --iscrypted $1$JlSBrxl.$ksXaF7TIE.70iV12//V4R0

There is also a networking section. In this case I am specifying that I want the operating system to use DHCP:

1network --onboot yes --bootproto=dhcp --activate

Also the packages section is quite useful. Here you can specify any packages you want to install during the operating system installation.

 1**%packages --ignoremissing --excludedocs
 2@core
 3sudo
 4net-tools
 5ntp
 6ntpdate
 7vim
 8wget
 9curl
10git
11yum-utils
12perl**

In Part 3 we will dive into variables in more detail!

Thanks for reading!