In this post, I will explain how I am using a freeware package called Packer to create SYSPREPed/generalised templates for Citrix Cloud / Windows Virtual Desktop (WVD) – including installing application/software packages from Azure Files.
My Requirement
Sometimes you need an image that you can quickly deploy. Maybe it’s for a scaled-out or highly-available VM-based application. Maybe it’s for a Citrix/Windows Virtual Desktop worker pool. You just need a golden image that you will update frequently (such as for Windows Updates) and be able to bring online quickly.
One approach is to deploy a Marketplace image into your application and then use some deployment engine to install the software. That might work in some scenarios, but not well (or at all) in WVD or Citrix Cloud scenarios.
A different, and more classic approach, is to build a golden image that has everything installed and then the VM is generalised to create an image file. That image file can be used to create new VMs – this is what Citrix Cloud requires.
Options
You can use classic OS deployment tools as a part of the solution. Some of us will find familiarty in these tools but:
- Don’t waste your time with staff under the age of 40
- These tools aren’t meant for the cloud – you’ll have to daisy chain lots of moving parts, and that means complex failure/troubleshooting.
Maybe you read about Azure Image Builder? Surely, using a native image building service is the way to go? Unfortunately: no. AIB is a preview, driven by scripting, and it fails by being too complex. But if you dig into AIB, you’ll learn that it is based on a tool called Packer.
Packer
Packer, a free tool from Hashicorp, the people behind Terraform, is a simple command line tool that will allow you to build VM images on a number of platforms, including Azure ARM. The process is simple:
- You build a JSON file that describes the image building process.
- You run packer.exe to ingest that JSON file and it builds the image for you on your platform of choice.
And that’s it! You can keep it simple and run Packer on a PC or a VM. You can go crazy and build a DevOps routine around Packer.
Terminology
There are some terms you will want to know:
- Builders: These are the types of builds that Packer can do – the platforms that it can build on. Azure ARM is the one I have used, but there’s a more complex/faster Builder for Azure called chroot that uses an existing build VM to build directly into a managed disk. Azure ARM builds a temporary VM, configures the OS, generalises it, and converts it into an image.
- Provisioners: These are steps in the build process that are used to customise your operating system. In the Windows world, you are going to use the PowerShell provisioner a lot. You’ll find other built in provisioners for Ansible, Puppet, Chef, Windows Restart and more.
- Custom/Community Provisioners: You can build additional provisioners. There is even a community of provisioners.
Accursed Examples
If you search for Windows Packer JSON Files, you are going to find the same file over and over. I did. Blog posts, powerpoints, training materials, community events – they all used the same example: Deploy Windows, install IIS, capture an image. Seriously, who is ever going to want an image that is that simple?
My Requirement
I wanted to build a golden image, a template, for a Citrix worker pool, running in Azure and managed by Citrix Cloud. The build needs to be monthly, receiving the latest Windows Updates and application upgrades. The solution should be independent of the network and not require any file servers.
Azure Files
The last point is easy to deal with: I put the application packages into Azure Files. Each installation is wrapped in a simple PowerShell script. That means I can enable a PowerShell provisioner to run multiple scripts:
Unverified Executables
set-location “HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains”
new-item “windows.net”
set-location “Windows.net”
new-item “myshare.file.core”
set-location “myshare.file.core”
new-itemproperty . -Name https -Value 2 -Type DWORD
The second piece of code will trust .EXE files:
set-location “HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies”
new-item “Associations”
set-location “Associations”
new-itemproperty . -Name LowRiskFileTypes -Value ‘.exe’ -Type STRING
SYSPREP Stalls
This one wrecked my head. I used an inline PowerShell provisioner to add Windows roles & features:
Thank you for sharing this article.
Would you be kind to share the contents of the two example scripts, install-adobeReader.ps1 and or install-office365ProPlus.ps1.
I am learning how to use Packer to create templates but have run into a problem with installing applications that reside on a network share and curious to find out the method you have has worked for you. I keep getting the below errors:
vsphere-iso: C:\Users\Administrator>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file “C:\Users\Administrator\script.ps1”
==> vsphere-iso: The argument ‘C:\Users\Administrator\script.ps1’ to the -File parameter does not exist. Provide the path to an existing ‘.ps1’ file as an argument to the -File parameter.
Thanks!
Hi, thanks for your article- useful as usual! Worth mentioning, that this step “Grab a copy of the community Windows-Update provisioner and place it in the same folder as Packer.exe. ” – this will not work if you are running packer windows-update task from azure devops.
Have you found a solution to upload this https://github.com/rgl/packer-plugin-windows-update/releases/download/v0.12.0/packer-plugin-windows-update_v0.12.0_x5.0_windows_amd64.zip into packer working directory in ADO ?
MS
What I did is place a HCL file in the Repo of the pipeline with this content:
packer {
required_plugins {
windows-update = {
version = “0.12.0”
source = “github.com/rgl/windows-update”
}
}
}
And added these to the pipeline YAML
– task: PackerTool@0
inputs:
version: 1.8.2
– task: CmdLine@2
inputs:
script: |
rem packer init
packer init template.pkr.hcl
Now the ‘Unknown provisioner’ error is gone.