How to Automate Windows Updates in VMware Templates with Packer

Save to My DOJO

How to Automate Windows Updates in VMware Templates with Packer

In our last post “Getting Started with Packer for VMware” we went over the basics of deploying a Windows Server 2016 template in vSphere. Let’s take it a step further and run some PowerShell scripts against our template during the Packer build phase to apply the usual business-standard configurations to the OS like disable Windows Firewall and disable old versions of TLS. This really shows some of the power of using Packer for automating the maintenance of template builds and it also shows how we are able to maintain our template with just code. Let’s get started!

Configuring Packer Build with PowerShell Script

First, we need to create a script that will run while building the template. Save the following PowerShell script to a .ps1 file. In our example I save it as build.ps1:

#disable Windows Firewalls
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False.

#Disable TLS 1.0
new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" -Name "TLS 1.0"
new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0" -Name "Server"
new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0" -Name "Client"
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client" -Name "Enabled" -Value 0
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client" -Name "DisabledByDefault" -Value 1
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" -Name "Enabled" -Value 0
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" -Name "DisabledByDefault" -Value 1
 
#Disable TLS 1.1
new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" -Name "TLS 1.1"
new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1" -Name "Server"
new-item -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1" -Name "Client"
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" -Name "Enabled" -Value 0
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" -Name "DisabledByDefault" -Value 1
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" -Name "Enabled" -Value 0
new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" -Name "DisabledByDefault" -Value 1

I saved the build.ps1 file to the same directory as my WindowsServer.json file. Next, we will add a provisioner section to the end of our WindowsServer.json file and specify that we want to run the build.ps1 script when building the template:

"provisioners": [
      {
        "type": "powershell",
        "script": "build.ps1"
      }
    ]

Automating Windows Updates Using Packer

Now we want to have packer automatically update our template with the latest Windows Updates, this is a huge benefit as we will be able to automate our template build each month and build a freshly updated template each time. First, we will need to install the Windows Update provisioner. There are multiple ways to install the provisioners, but in this example, we will just simply place in our packer.exe location. Packer will automatically look for the packer-provisioner-windows-update.exe file when it runs:

Packer

Next, we’ll add another provisioner to our WindowsServer.json configuration file. These settings are basically telling the OS to install all Windows Updates but exclude any that are in “preview” status:

"provisioners": [
      {
        "type": "powershell",
        "script": "build.ps1"
      },
      {
        "type": "windows-update",
        "search_criteria": "IsInstalled=0",
        "filters": [
            "exclude:$_.Title -like '*Preview*'",
            "include:$true"
        ],
        "update_limit": 25
    }
    ]

So now we have our build.ps1 script and our Windows Updates that will run when we build our new template.

Adding Variables to Configuration

It’s best practice to omit sensitive information like passwords and secrets in our Packer configuration. We ultimately what to have our Packer code up in source control and it’s not best practice to store sensitive data there. We can use variables instead and inject the values either through a variables file or if we are using a CI/CD pipeline like Azure DevOps we can just set a variable group and use that in the pipeline. We will configure our variables in our Packer configuration by adding the following to the top of the config. Also, note that we are listing “sensitive-variables” which prevents Packer from writing the value of these variables in logs:

"variables": {
      "VCPassword": "",
      "WinRMPassword": ""
    },

"sensitive-variables": ["VCPassword", "WinRMPassword"],

Then we will create a variables file with the actual values of our variables. I named mine “variables.json”:

{
  "VCPassword": "P#@[email protected]",
  "WinRMPassword": "[email protected]"
}

Now we’ll reference this file when we run our Packer build.

 

Deploying the Build

With all the additions made to our configuration we can now have a complete version:

{
  
    "variables": {
      "VCPassword": "",
      "WinRMPassword": ""
    },

    "sensitive-variables": ["VCPassword", "WinRMPassword"],

    "builders": [
      {
        "type": "vsphere-iso",
  
        "vcenter_server": "vcenter.lukelab.lcl",
        "insecure_connection": "true",
        "username": "[email protected]",
        "password": "{{user `VCPassword`}}",
        "cluster": "Luke-HA-DRS",
        "host": "esxi1.lukelab.lcl",
        
        "communicator": "winrm",
        "winrm_username": "Administrator",
        "winrm_password": "{{user `WinRMPassword`}}",

        "vm_name":  "packerimage",
        "convert_to_template": "true",
        "cpus": "2",
        "ram": "4096",
        "network": "VM Network",
        "network_card": "vmxnet3",
        "datastore": "ESXi1-Internal",
        "disk_controller_type":  "lsilogic-sas",
	"guest_os_type": "windows9Server64Guest",
      "disk_thin_provisioned": true,
        "disk_size": "32768",
	"iso_paths": [
        "[ESXi1-Internal] ISO/Windows/Windows_Server_2016.ISO",
        "[ESXi1-Internal] ISO/Windows/VMwareTools.iso"
      ],
      "floppy_files": [
        "setup/autounattend.xml",
        "setup/setup.ps1",
        "setup/vmtools.cmd"
      ]
        
      }
    ],

    "provisioners": [
      {
        "type": "powershell",
        "script": "build.ps1"
      },
      {
        "type": "windows-update",
        "search_criteria": "IsInstalled=0",
        "filters": [
            "exclude:$_.Title -like '*Preview*'",
            "include:$true"
        ],
        "update_limit": 25
    }
    ]
  }

We will go ahead and run our packer build and reference our variables file by using the -var-file argument:

packer builde -var-file .\Variables.Json .\WindowsServer.Json

Automating windows updates in VMware Templates with Packer

During the template provisioning, we can see that the PowerShell script we created is deployed and Windows Updates are running and updating the OS with the latest patches.

Conclusion

Now, we can take this configuration and apply the same scripts and Windows Update plugin to Images in other environments like AWS, Azure, or GCP. All we have to do is add another builder’s section in the JSON file for Azure or AWS and the Images in both those systems and VMware will start building IN PARALLEL. Hashicorp is really taking the cloud-agnostic approach to the next level and Packer is just one more tool in our toolbox that allows us to not only automate our template builds but also to use the same code and process for updating our templates in every environment. The best part is that this is an open-source tool and is completely free. If you’re not using Packer to manage your VM templates today you need to get on board!

Let me know in the comments below on how you’ve started using Packer or if you’ve been using it in your environment!

Altaro VM Backup
Share this post

Not a DOJO Member yet?

Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!

Leave a comment

Your email address will not be published.