Introduction
HashiCorp Packer is an open-source tool that automates the creation of identical machine images for multiple platforms from a single configuration file. Building custom Windows Server 2016 images with Packer ensures that every virtual machine deployed in your environment starts from a hardened, pre-configured baseline — with all Windows updates, security settings, required software, and monitoring agents pre-installed. This eliminates configuration drift and dramatically speeds up VM provisioning in Hyper-V, VMware, Azure, AWS, and other platforms.
Installing Packer on the Build Host
Install Packer on a Linux build server (or Windows) that has access to your hypervisor:
# On Linux build host (Ubuntu/Debian)
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list
apt-get update && apt-get install -y packer
# Verify installation
packer version
# Install Packer plugins for Hyper-V and Azure
packer plugins install github.com/hashicorp/hyperv
packer plugins install github.com/hashicorp/azure
Creating the Packer HCL Template for Hyper-V
Write a Packer HCL2 configuration file to build a Windows Server 2016 image on Hyper-V:
cat > /packer/ws2016-hyperv.pkr.hcl << 'EOF'
variable "iso_url" {
default = "file:///isos/en_windows_server_2016_x64.iso"
}
variable "iso_checksum" {
default = "sha256:1ce702a578a3cb1ac3d14873980838590f06d5b7101c5daaccbac9d73f1fb50f"
}
source "hyperv-iso" "ws2016" {
iso_url = var.iso_url
iso_checksum = var.iso_checksum
vm_name = "WS2016-BaseImage"
cpus = 4
memory = 4096
disk_size = 61440
switch_name = "External Switch"
generation = 2
secure_boot = true
guest_additions_mode = "disable"
headless = true
communicator = "winrm"
winrm_username = "Administrator"
winrm_password = "Temp@dmin2016!"
winrm_use_ssl = false
winrm_timeout = "60m"
floppy_files = ["./answer_files/Autounattend.xml"]
boot_wait = "60s"
shutdown_command = "shutdown /s /t 10 /f /d p:4:1 /c 'Packer Shutdown'"
}
build {
sources = ["source.hyperv-iso.ws2016"]
provisioner "powershell" {
scripts = [
"scripts/01-initial-setup.ps1",
"scripts/02-windows-updates.ps1",
"scripts/03-install-agents.ps1",
"scripts/04-security-hardening.ps1",
"scripts/05-sysprep.ps1"
]
}
post-processor "manifest" {
output = "manifest.json"
strip_path = true
}
}
EOF
Writing the Autounattend.xml Answer File
Create the Windows Setup answer file to automate the OS installation:
mkdir -p /packer/answer_files
cat > /packer/answer_files/Autounattend.xml << 'EOF'
en-US
en-US
en-US
en-US
EFI1100
MSR216
Primary3true
0true
03
true
Never
EOF
Writing Provisioner Scripts
Create PowerShell scripts that Packer runs inside the VM after installation:
mkdir -p /packer/scripts
# 01-initial-setup.ps1 — Disable unnecessary services, configure WinRM
cat > /packer/scripts/01-initial-setup.ps1 < /packer/scripts/04-security-hardening.ps1 << 'EOF'
# Require NTLMv2
Set-ItemProperty 'HKLM:SYSTEMCurrentControlSetControlLsa' -Name LmCompatibilityLevel -Value 5
# Enable Windows Firewall on all profiles
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
# Enable audit logging
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Account Logon" /success:enable /failure:enable
# Disable SMBv1
Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force
# Set minimum TLS to 1.2
$tls12 = 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Server'
New-Item -Path $tls12 -Force | Out-Null
Set-ItemProperty -Path $tls12 -Name Enabled -Value 1
Set-ItemProperty -Path $tls12 -Name DisabledByDefault -Value 0
EOF
Building the Image
Run Packer to build the Windows Server 2016 image:
cd /packer
# Validate the template
packer validate ws2016-hyperv.pkr.hcl
# Build the image (verbose output)
PACKER_LOG=1 packer build ws2016-hyperv.pkr.hcl 2>&1 | tee /var/log/packer-ws2016.log
# Check the output manifest
cat manifest.json | python3 -m json.tool
Summary
Packer automates the creation of standardised, security-hardened Windows Server 2016 base images that eliminate configuration drift across your infrastructure. With an Autounattend.xml answer file, layered PowerShell provisioner scripts, and a declarative HCL template, you can produce identical gold images for Hyper-V, VMware, Azure, or AWS in a fully automated pipeline. These base images form the foundation for immutable infrastructure and significantly accelerate VM deployment times in any environment.