Packer Example for Windows
Getting Started
You can get started quickly by using Packer’s simple getting started guide, but you’ll soon want to delve into the documentation for more options and examples.
Let’s install it and create our first image!
You can find all example files in my GitHub repository here: https://github.com/adamrushuk/Packer-Templates
Installation
Using Chocolatey, installing Packer is as easy as running:
choco install packer -y
Clone my GitHub repository if you want to follow along:
git clone git@github.com:adamrushuk/Packer-Templates.git
TL;DR - Shut up and give me the goods!
If you really just want to see Packer in action, make sure you’ve cloned the git repository in the Installation step above, then run the Invoke-Packer.ps1 wrapper script: .\Invoke-Packer.ps1
If you’re interested in the step-by-step breakdown, read on!
Step 1: Create the base image
First we’ll create a base image by passing our first JSON template to the build command:
packer build .\vb-win2012r2-base.json
Breakdown
The above command starts the build process in the following order:
Builders Section
- Packer first checks the
packer_cachefolder to see if the ISO specified inISO URLhas already been downloaded. If not, it downloads the ISO. - The
output_directoryfolder is checked to see if empty, or can be overwritten ifpacker build -force <JSONTemplate>was used.
This check is ignored if -force is used, eg:packer build -force <JSONTemplate>. - A VM is created in VirtualBox with the specified hardware settings.
- A virtual floppy disk is attached containing the files specified in
floppy_files. - The VM is powered on.
- As Windows boots for the first time it notices
Autounattend.xmlin the root of the floppy drive, which actions several steps including:- Selecting the
Windows Server 2012 R2 STANDARDOS version. - Creating a local user account called
vagrantand adding it to the localadministratorsgroup. - Executing the
a:\Boxstarter.ps1script.
- Selecting the
- The
a:\Boxstarter.ps1script installsChocolateyandBoxstarter, then executes thea:\Package.ps1script. - The
a:\Package.ps1script:- Enables Remote Desktop.
- Installs critical Windows Updates.
- Removes the pagefile.
- Updates Firewall and enables WinRM.
- Packer connects via WinRM and moves on to the Provisioners Section.
Info: Boxstarter will log all package activity output to $env:LocalAppData\Boxstarter\boxstarter.log on the guest. [TBC]
Warning: winrm_timeout must be set high enough to account for the Windows Updates which can take 4hrs+. I’ve now set to 12h, as my first build failed.
Provisioners Section
Install-VirtualBoxGuestAdditions.ps1is the only script used in this section, which simply installs the VirtualBox Guest Additions software.
Shutdown
After the Provisioners section is complete, the shutdown command executes:
shutdown /s /t 10 /f /d p:4:1 /c "Packer Shutdown"
The resulting artifacts of .ovf and .vmdk VM files should be saved in the specified output_directory: output-win2012r2-base.
This step took ~4 hours.
Step 2: Create the PowerShell 5 image
Now let’s create another image with PowerShell 5 installed by passing our second JSON template to the build command:
packer build .\vb-win2012r2-powershell5.json
Having images for both PowerShell 4 and PowerShell 5 will enable us to target both versions when running our tests using a product like Test-Kitchen.
Breakdown
The above command starts the build process in the following order:
Builders Section
- The
output_directoryfolder is checked to see if empty.
This check is ignored if -force is used, eg:packer build -force <JSONTemplate>. - The
source_pathfolder is checked to see if the specified OVF file exists, eg:output-win2012r2-base/win2012r2-base.ovf. - A VM is created in VirtualBox by importing the
output-win2012r2-base/win2012r2-base.ovffile from Step 1 (Create the base image). - The VM is powered on and Packer connects via WinRM.
Provisioners Section
Install-PowerShell5.ps1simply installs PowerShell 5:choco install powershell -y.windows-restartensures the VM is rebooted after the PowerShell 5 installation.cleanup.ps1will:- Remove temp folders/files.
- Remove unwanted Windows Update files.
- Defrag the C drive.
- Zero out freespace.
Shutdown
After the Provisioners section is complete, the shutdown command executes:
shutdown /s /t 10 /f /d p:4:1 /c "Packer Shutdown"
The resulting artifacts of .ovf and .vmdk VM files should be saved in the specified output_directory, eg: output-win2012r2-powershell5.
This step took ~20 minutes.
Step 3: Sysprep and export to a Vagrant box
The final step is to sysprep the previous two images (from Steps 1 and 2) and export them to a Vagrant box - though I’ll just cover one example using the image from Step 2.
Let’s pass the third JSON template to the build command:
packer build .\vb-win2012r2-export-vagrant.json
Breakdown
The above command starts the build process in the following order:
Builders Section
- The
output_directoryfolder is checked to see if empty.
This check is ignored if -force is used, eg:packer build -force <JSONTemplate>. - The
source_pathfolder is checked to see if the specified OVF file exists, eg:output-win2012r2-powershell5/win2012r2-powershell5.ovf. - A VM is created in VirtualBox by importing the
./output-win2012r2-powershell5/win2012r2-powershell5.ovffile from Step 2 (Create the PowerShell 5 image). - A virtual floppy disk is attached containing the files specified in
floppy_files. - The VM is powered on and Packer connects via WinRM.
Provisioners Section
Set-Sysprep.ps1is the only script used in this section, which completes these two actions:- Copies
a:\UK-postunattend.xmltoC:\Windows\Panther\Unattend\unattend.xml - Copies
a:\SetupComplete-2012.cmdtoC:\Windows\setup\scripts\SetupComplete.cmd
- Copies
These two files are used once the Vagrant box is powered on for the first time after the sysprep during the Packer shutdown.
unattend.xml configures:
- Locale and language settings to
en-GB. - Timezone to
GMT Standard Time. - A local user account called
vagrantand adding it to the localadministratorsgroup. - Various annoying GUI settings to be disabled.
SetupComplete.cmd simple enables WinRM: netsh advfirewall firewall set rule name="WinRM-HTTP" new action=allow, as the Packer shutdown command below disables WinRM.
Shutdown
After the Provisioners section is complete, the shutdown command executes:
a:/PackerShutdown.bat which will disable WinRM so Vagrant doesn’t get confused during the first reboot after the sysprep:
REM Disable WinRM
call winrm set winrm/config/service/auth @{Basic="false"}
call winrm set winrm/config/service @{AllowUnencrypted="false"}
netsh advfirewall firewall set rule name="WinRM-HTTP" new action=block
:: Sysprep and shutdown
C:/windows/system32/sysprep/sysprep.exe /generalize /oobe /unattend:C:/Windows/Panther/Unattend/unattend.xml /quiet /shutdown
The resulting artifacts of .ovf and .vmdk VM files should be saved in the specified output_directory: /output-win2012r2-powershell5-vagrant.
Post-processors Section
The vagrant post-processor will action the following:
- Import the
.ovfand.vmdkartifacts from theprovisionersection. - Produce a Vagrant box using the
windows-template.vagrantfiletemplate. - As
"keep_input_artifact": trueis specified, the.ovfand.vmdkVM files from theprovisionersection will be retained, but you can set this to false if preferred. I like to keep them for troubleshooting if required.
This step took ~20 minutes.
Summary
We’ve gone over the separate steps you can take to create Packer images, and after about 5 hours you should now have a shiny new Vagrant box to play with: Win2012R2-Std-WMF5-Full.box
Now you can build upon these templates and customise to your liking.
Reference
Make sure you visit these awesome blogs to see where most of the examples / scripts came from:
Leave a comment