This repo contains code that can generate Packer templates designed to build and package Windows templates for use with Vagrant boxes. The overall goal is to cover all supported Windows OS' included Windows Server, Server Core, Server Nano and the Desktop OS' but the main focus is on the Windows Server images.
Each image is designed to be;
- Fully updated at the time of creation
- As small as can be possible for a Windows image
- Contain minimal tools useful for Windows development such as the sysinternals suite
- Enable WinRM (HTTP and HTTPS) and RDP on creation in Vagrant allowing other tools to interact with a new image without manual interaction
- Also include the latest Win32-OpenSSH in the image that starts up automatically
- Each image contain the maximum amount of time available on a Windows evaluation image (usually 180 days) without prompting for a key
The blog post Using Packer to Create Windows Images contain a more detailed guide on this process and how it all works. Feel free to read through it if you want to understand each component and how they fit together more.
To use the scripts in this repo you will need the following;
- Packer >= 1.0.0, 1.2.4 is required for Hyper-V with Server 2008 R2 support
- Ansible >= 2.7.0
mkisofsfor Windows this needs to be installed in WSL where Ansible is located
- BeautifulSoup4 to retrieve the latest Windows Updates for the build
One of the following hypervisers as defined by
man_packer_setup_host_type: 2008-x64, Ansible will extract the
evaluation ISO from a self extracting archive. This requires the
package to be installed. If you don't want to install this package, manually
extract the ISO on another box and specify the path under
unrar, you can run one of the commands below
depending on your distribution;
# for Debian/Ubuntu sudo apt-get install mkisofs unrar # for RHEL/CentOS sudo yum install mkisofs sudo yum localinstall --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm https://download1.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-7.noarch.rpm sudo yum install unrar # for Fedora sudo dnf install mkisofs sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm sudo dnf install unrar # for MacOS (requires Homebrew) brew install cdrtools unrar
How to Run
To create an image, the process is split up into 2 phases
- Create the files required for Packer to build and provision an image
- Run Packer based on the files created above
Create Packer Files
For Packer to provision a Windows host it first needs an
file and bootstrapping script to configure the base host requirements needed by
Ansible. Instead of having them already stored in the repo, they are
dynamically created by Ansible based on the configuration provided.
To create the files for a particular host type run;
ansible-playbook packer-setup.yml -e man_packer_setup_host_type=<host type> # see below what can be used for <host type> but to create the Packer files for a Server 2012 R2 image run ansible-playbook packer-setup.yml -e man_packer_setup_host_type=2012r2 # specify custom Chocolatey packages to install instead of vim and sysinternals on the image ansible-playbook packer-setup.yml -e opt_packer_setup_packages='["pstools", "notepadplusplus"]' # when running on Windows, you can run this from PowerShell like bash.exe -ic "ansible-playbook packer-setup.yml -e man_packer_setup_host_type=2012r2 -e opt_packer_setup_builder=hyperv"
After running the playbook, a folder which is named after the value of
man_packer_setup_host_type will be created and it will contain the following
iso/Autounattend.xml: The answer file used by Windows during the initial install
iso/bootstrap.ps1: A PowerShell script that is run after the initial install to configure the host required by Ansible
iso/*: Other files used in the bootstrapping process like hotfixes and updates required to configure WinRM
configure-hyperv-network.ps1: Used in the Hyper-V builder to set the correct IP for Ansible's inventory file
description.md: The changelog description of that current build
hosts.ini: An Ansible inventory file containing the info required by Ansible during the provisioning phase
packer.json: The Packer definition file the contains all the info that Packer needs to build the image
secondary.iso: The secondary ISO file used to store the
bootstrap.ps1, and other files used in that process
vagrantfile.template: The templated Vagrantfile that is embedded in the Vagrant box produced
opt_packer_setup_builder=hyperv, this process will also create the
Hyper-V switch defined by
opt_packer_setup_hyperv_switch if it does not
exist. This switch is created as an External Network type with the host OS
allowed to share with the guest. This type of switch is required for 2 reasons;
- Allows the Windows host to access the guest
- Allows the guest to access the internet for things like updates and downloading packages
An Internal Network type covers the first point but you need an External Network type to access the internet.
This switch is NOT cleaned up afterwards automatically.
The following parameters must be set using the
man_packer_setup_host_type: The host type string that tells packer what to build, see options below
You can set the host type to the following values
2008-x86: Windows Server 2008 Standard 32-bit
2008-x64: Windows Server 2008 Standard 64-bit
2008r2: Windows Server 2008 R2 Standard
2012: Windows Server 2012 Standard
2012r2: Windows Server 2012 R2 Standard
2016: Windows Server 2016 Standard
2019: Windows Server 2019 Standard
The following host types can also be used but it requires the ISO to be
manually downloaded and set with
opt_packager_setup_iso_path. Microsoft does
not offer evaluation ISOs for these builds so it won't be part of the public
1709: Windows Server Build 1709 Standard
1803: Windows Server Build 1803 Standard
The following are optional parameters set using the
-e argument and can
change the way Packer builds the images in the next step;
opt_packer_setup_builder: The Packer builder to use, defaults to
hypervwhen running on Windows.
opt_packer_setup_disk_size_mib: The size in mebibytes' (
MiB) of the OS disk to create (default:
opt_packer_setup_headless: Used for debugging, will display the Windows console during the build if set to
opt_packer_setup_iso_path: The local path to the install Windows ISO, this means packer will use this instead of downloading the pre-set evaluation ISO from the internet.
opt_packer_setup_iso_wim_label: The WIM image name to use when installing Windows from an ISO, the process defaults to the Standard edition if not set.
vagrant) The name of the user to create in the provisioning process, this is the only user that will available in the image created as the builtin Administrator account is disabled.
vagrant) The password for
opt_packer_setup_username, this password is also set for the builtin Administrator account even though it is disabled in the image.
opt_packer_setup_product_key: The product key to use when installing Windows, do not set this unless you know what you are doing.
packer-windoze) The name of the Hyper-V switch to create. There shouldn't be a need to change this unless you know what you're doing.
sysinternals) Override the default Chocolatey packages that are installed on each image. This should be a list of valid Chocolatey package names that are packes to the
win_chocolateymodule, see the examples for more details.
To add a post-processor to upload to Vagrant Cloud, add in the following 3 variables;
opt_packer_setup_access_token: The acces token for the Vagrant Cloud API, this is set to the
access_tokenkey in the packer build file.
opt_packer_setup_box_tag: The shorthand tag for the map that maps to Vagrant Cloud, this is set to the
box_tagkey in the packer build file.
opt_packer_setup_version: The version number for the box which is validated based on semantic versioning, this is set to the
versionkey in the packer build file and if ommitted then the latest version in the changelog is used.
Create Images with Packer
Once the packer files have been created under it's own folder, Packer can now be used to create the image. Run the following to start the process
packer build -force <host_type>/packer.json # replace <host_type> with the type to build, e.g. for Server 2012 R2 packer build -force 2012r2/packer.json
This process takes a looong time to finish as Packer will download the ISO, install Windows and finally configure Windows. The best thing to do is to run this overnight or as a background process.
Once complete a file with the
.box extension will be created in the same
packer.json file is located in. This file can be added to Vagrant
vagrant box add <filename>.box or can be shared with others using your own
methods. The filename is dependent on the builder that was used. When
virtualbox then it will be
hyperv will be
What It Does
Here is a brief step by step overview of what actually happens with the images
- Packer start a VM under the hypervisor and attaches the ISO that contains the
bootstrap.ps1, and other bootstrap files
- Windows starts the install process and configures it according to the
- After the install is complete Windows will auto login to the
vagrantuser and run the
- The bootstrap script will ensure that PowerShell v3 or greater is installed, WinRM is setup and other things
- Packer detects that WinRM is up and running and starts the provision process which is the Ansible playbook
- Ansible will then install all available updates and reboot accordingly (this step can take hours so be prepared to wait)
- Some personalisation tweaks occur such as showing hidden files and folders, file extensions and installing the sysinternals tools
- Will try to cleanup as much of the WinSXS folder as possible (older hosts are limited in how much it can do)
- Will remove all non enabled Features if Features on Demand is supported (Server 2012 and newer)
- Remove pagefile, temp files, log files that are not needed. Defrags the disk and 0's out empty space for the compression to work properly
- Setup the sysprep template files
- Remove the WinRM listeners and run the sysprep process to shutdown the host
From this point Packer will create an image of the OS which can be used by Vagrant. When Vagrant first starts up the image, it will automatically log on and, rearm the activation key and recreate the WinRM listeners.
- Windows Server Core images
- Windows Server Nano images
- Windows 10 32 and 64 bit
- Look at supporting parallel builds
- Look at slipstreaming Windows updates into the evaluation ISO's instead of running the updates from scratch each time
- Look at supporting local WSUS servers during the Update phase to save time and bandwidth