Building a Windows Golden Image with HashiCorp Packer

Last updated: March 4, 2026


Table of Contents


Why I Switched to Packer for Golden Images

Before I started using Packer, my image process was entirely manual: install Windows Server, click through the GUI, run some PowerShell scripts by hand, install VirtIO, install Cloudbase-Init, Sysprep, clone the disk image. The whole thing took 2–3 hours and was completely undocumented. When I needed to rebuild for a new Windows Server version or to include a security patch, I started from scratch.

The other problem was drift. VM templates built manually in Prism Element had no audit trail. I could not tell what was installed, who built them, or when the last patch was applied.

Packer solves both problems. The entire image is defined in version-controlled HCL files. Every build is reproducible. CIS benchmark hardening is applied automatically. The final image is uploaded to the Nutanix Image Service and tagged with a version. Old images are cleaned up by policy.

This article documents my full Packer setup for building a hardened Windows Server 2022 golden image on Nutanix AHV CE.


How Packer Works with Nutanix AHV

Packer uses the nutanix builder plugin, developed by the Nutanix Cloud Native team. The build flow is:

The key difference from a manual process: steps 2–10 are fully automated and idempotent. The same HCL produces the same image every time.


Prerequisites

Requirement
Notes

Packer 1.11+

brew install packer or download from packer.io

Nutanix Packer Plugin

packer plugins install github.com/nutanix-cloud-native/nutanix

Prism Central 2023.x+

Packer communicates with the v3 API

WinRM reachable from Packer host

Packer needs network access to the VM's port 5985

Windows Server 2022 ISO

Uploaded to Prism Central Image Service

Nutanix VirtIO ISO

Downloaded from Nutanix Portal → Tools & Firmware

~80 GB free in storage container

For the temporary build VM

Verify Packer Installation


Project Structure


Installing the Nutanix Packer Plugin

The plugin binary is stored at ~/.config/packer/plugins/.


Preparing the Autounattend.xml

The autounattend.xml file drives the unattended Windows Server installation. Packer attaches it as a second CD-ROM which the Windows installer automatically detects.

Image index 2 selects Windows Server 2022 Standard (Desktop Experience). Use index 1 for Core edition. Run Get-WindowsImage -ImagePath D:\sources\install.wim on a Windows machine to list all available indexes in your ISO.


Writing the Packer HCL Template


Variables File

Add to .gitignore:


Provisioners – Hardening and Software Installation

01-install-virtio.ps1

02-windows-update.ps1

03-install-cloudbase-init.ps1

04-harden-os.ps1

05-install-base-tools.ps1

99-sysprep.ps1


Running the Packer Build

Expected Output


Using the Golden Image in AHV

After a successful build, the image win2022-golden-2026.03.04 appears in:

Create a VM Directly from the Image

Use in a Blueprint

In your NCM Self-Service Blueprint substrate, reference the image by name:

Or in the Prism Central Blueprint GUI:

Because Cloudbase-Init is embedded in the image, the Blueprint's Sysprep guest customization script will be read automatically on first boot — hostname, password, and user-data all applied without any manual steps.


CI/CD Pipeline for Image Rebuilds

I rebuild the golden image monthly (or immediately after a critical CVE) using a GitLab CI/CD pipeline.

Store secrets in GitLab CI/CD Variables (masked):

  • NUTANIX_USER, NUTANIX_PASSWORD, NUTANIX_PC

  • NUTANIX_CLUSTER, NUTANIX_SUBNET

  • WINRM_BUILD_PASSWORD

  • SLACK_WEBHOOK_URL


Versioning and Lifecycle Management

Naming Convention

Tag images with metadata via Prism Central API after build:

Retention Policy

Keep the last 3 golden images; delete older ones automatically via a cleanup script:


Troubleshooting

Symptom
Cause
Fix

Packer times out waiting for WinRM

Autounattend.xml not found or VirtIO driver path wrong, Windows install stalled

Attach via Prism console to see the installer state; verify autounattend.xml CD label and VirtIO driver paths match ISO structure

Error: "No disk found" during Windows install

VirtIO SCSI driver not loaded in windowsPE pass

Check drive letter of VirtIO ISO in DriverPaths (E: vs F:); verify viostor\2k22\amd64 path exists in ISO

WinRM auth failure

Password mismatch between autounattend.xml and Packer winrm_password

Keep both values in sync; autounattend sets the build-time Administrator password, Packer connects with the same value

Sysprep fails: "A fatal error occurred while trying to Sysprep the machine"

Windows Updates pending reboot, or .NET install incomplete

Add extra windows-restart provisioner before Sysprep; disable Windows Update service cleanup before running Sysprep

Image not appearing in Prism Central after build

force_deregister = true removed old image but upload failed

Check Packer output for API errors; verify Prism Central has enough storage in the target container

Cloudbase-Init not running on first VM boot

Sysprep ran without Cloudbase-Init installed, or service is disabled

Verify 03-install-cloudbase-init.ps1 succeeded in Packer build log; check Cloudbase-Init service startup type in the image

Build VM left behind after failed run

Packer crashed before cleanup

Manually delete packer-build-win2022-* VMs from Prism Element; use force_deregister and handle cleanup in CI on failure


Next Steps


Tags: Nutanix, AHV, Packer, HashiCorp, Golden Image, Windows Server 2022, Cloudbase-Init, VirtIO, Sysprep, Autounattend, CI/CD, Image Pipeline

Last updated