While it supports Windows and Linux, creating an OS image is vastly different between the two. In this article, I will focus on how Packer is used for Windows OS image creation.
As I wrote in a previous article, Packer is a Hashicorp, open-sourced operating system image build tool. The specialty of Packer is the ability to create an artifact to multiple platforms (AWS, Azure, VMware etc.), all from one configuration. In addition, Packer supports the creation of both Linux and Windows images, allowing for a single method for image creation.
When learning a new technology, I find that looking at examples of how others use it is very helpful. The best resource I have found for using Packer with Windows is Stefan Scherer’s Github repository which is a fork of Joe Fitzgerald’s repository. In these two repositories you will find great examples of how Windows builds are automated using a combination of tools. I will use one of Stefan’s Packer templates for Windows 10 to illustrate how Packer works with Windows.
Perhaps the most important aspect of automating a Windows OS installation is the autounattend.xml file. It is important to note that this is not specific to Packer, as anyone can use this to automate Windows installation. By default, when you boot to a Windows OS installation disk, Windows will prompt the user with installation options, such as choosing the disk to install Windows to. All of these options can be set in the autounattend.xml file, which needs to be located on a removable drive. To do this in Packer, you can mount these on the virtual machine via a floppy drive. This is an example of doing this in the builder section on a Packer template:
"shutdown_command": "shutdown /s /t 10 /f /d p:4:1 /c \"Packer Shutdown\"",
You can see in the floppy files section, we set the local file /answer_files/autounattend.xml to be copied and mounted. Inside the autounattend.xml, you can make various configurations to automate the Windows prompts during OS installation. For instance, this sets the autologin account using “vagrant” for the username and password:
There is also a section in autounattend.xml to run commands on the first logon after initial Windows OS installation. This is where a lot of your configuration can occur as it supports both batch and PowerShell scripts. In this example, a PowerShell script will run called win-updates.ps1 which will install Windows updates onto the VM.
You will find there is a lot that can be set in the autounattend file, so for a deeper inside into autounattend.xml take a look at one of Stefan’s answer files here.
SSH is the common way for Packer to communicate with a VM. In Windows, WinRM is the more usual method of remote communication although using OpenSSH is possible as well. As you can see in the Packer template in the previous section, you can set the authentication to WinRM in the Packer template:
By default, in Windows, WinRM requires SSL encryption between two non-domain joined computers. Although this is insecure, the easiest way to allow communication between your Packer host and build VM is to allow unencrypted traffic (HTTP). This can be done by using Stefan’s script from Github here.
Using ISO Files
The basic building block of creating a Windows image is to use a Windows installation ISO. For testing, you can use trial ISOs from Microsoft or volume licensing ISOs that are made available to your organization. In the Packer template, you can set three fields for configuring an ISO (although you can also pass them to the command packer build as well at runtime) for the ISO file, checksum and checksum type. Here in Stefan’s Windows 10 template we use user variables in the build but also set them so they are not actually necessary.
To show a quick demonstration, I have downloaded Stefan’s repo locally and will run packer build. This will build my Windows 10 image and then create a Vagrant box as well by default by downloading a Windows 10 trial ISO. Here is a sample output. You will see the ISO downloading as well as the scripts being copied to the floppy drive of the VM:
Dans-MacBook-Pro:packer-windows-my dan$ ~/packer build -only=virtualbox-iso windows_10.json
virtualbox-iso output will be in this color.
==> virtualbox-iso: Downloading or copying ISO
virtualbox-iso: Downloading or copying: https://software-download.microsoft.com/download/pr/17134.1.180410-1804.rs4_release_CLIENTENTERPRISEEVAL_OEMRET_x64FRE_en-us.iso
virtualbox-iso: Download progress: 90%
virtualbox-iso: Download progress: 91%
virtualbox-iso: Download progress: 92%
virtualbox-iso: Download progress: 94%
virtualbox-iso: Download progress: 95%
virtualbox-iso: Download progress: 96%
virtualbox-iso: Download progress: 97%
virtualbox-iso: Download progress: 99%
virtualbox-iso: Download progress: 100%
virtualbox-iso: Download progress: 100%
==> virtualbox-iso: Creating floppy disk...
virtualbox-iso: Copying files flatly from floppy_files
virtualbox-iso: Copying file: ./answer_files/10/Autounattend.xml
virtualbox-iso: Copying file: ./floppy/WindowsPowershell.lnk
virtualbox-iso: Copying file: ./floppy/PinTo10.exe
virtualbox-iso: Copying file: ./scripts/fixnetwork.ps1
virtualbox-iso: Copying file: ./scripts/disable-screensaver.ps1
virtualbox-iso: Copying file: ./scripts/disable-winrm.ps1
virtualbox-iso: Copying file: ./scripts/enable-winrm.ps1
virtualbox-iso: Copying file: ./scripts/microsoft-updates.bat
virtualbox-iso: Copying file: ./scripts/win-updates.ps1
virtualbox-iso: Done copying files from floppy_files
virtualbox-iso: Collecting paths from floppy_dirs
virtualbox-iso: Resulting paths from floppy_dirs : 
virtualbox-iso: Done copying paths from floppy_dirs
==> virtualbox-iso: Creating virtual machine...
==> virtualbox-iso: Creating hard drive...
==> virtualbox-iso: Attaching floppy disk...
==> virtualbox-iso: Creating forwarded port mapping for communicator (SSH, WinRM, etc) (host port 4194)
==> virtualbox-iso: Executing custom VBoxManage commands...
virtualbox-iso: Executing: modifyvm windows_10 --memory 2048
virtualbox-iso: Executing: modifyvm windows_10 --cpus 2
==> virtualbox-iso: Starting the virtual machine...
==> virtualbox-iso: Waiting 6m0s for boot...
==> virtualbox-iso: Typing the boot command...
==> virtualbox-iso: Waiting for WinRM to become available...
virtualbox-iso: WinRM connected.
While Linux may be the more supported OS for building Packer images, Windows is certainly an option as well. Using some unattended methods, Packer does a great job at creating clean Windows image builds.