Packer Packer

Last Updated on May 18, 2024 by Arnav Sharma

Packer is an open-source tool that enables you to create identical machine images for multiple platforms from a single source template. A common use case is creating “golden images” that teams across an organization can use in cloud infrastructure.

Ref. : Packer by HashiCorp

For customization of Azure, refer: Azure arm – Builders | Packer by HashiCorp

Getting Started:

Download Packer: Downloads | Packer by HashiCorp

Packer has used a JSON template for its configuration in past, but now Packer is transitioning to a new format that uses HCL2. HCL is the same language that is used in Terraform.

Packer Template

  1. Source Block: This contains the source (azure, AWS, GCP, VMWare etc) , configuration block and plugins.

There are 50-100 different settings to customize the image and process which are documented here:

Azure arm – Builders | Packer by HashiCorp

2. Build block: Contains builders, provisioners, and post-processors used to create a specific image artifact. There are builders specific to the image being built as well as the target environment.

3. Variable block: Similar to terraform, these are the variable to be used and can be specified in a different file.

In the above example, I have placed the code on the .pkl.hcl file and then have two more files – one PowerShell script and the second one to pass values for variables.

Some common commands:

  • packer version : Output of packer version
  • packer fmt tmpl.pkr.hcl: Template file formatting
  • packer validate tmpl.pkr.hcl : Template file validation
  • packer build tmpl.pkr.hcl: Build image
  • packer build -debug tmpl.pkr.hcl: Build & debug

Running/building the image:


Packer creates a temp resource group, a VM with required resources (IP, NIC, vNET etc etc) and then captures the image for it.

Resource Group (temp) with resources:

Once the image is created, the image is placed in the RG specified in the code.

The image can then be used to create a VM or can be registered in the gallery.

Sample Code that I used:


variable "subid"{
    type    = string
    default = null
variable "tenant" {
    type    = string
    default = null
variable "rgname" {
    type    = string
    default = null
variable "username" {
    type    = string
    default = null
variable "password" {
    type    = string
    default = null
variable "capturenamename" {
    type    = string
    default = null
variable "location" {
    type    = string
    default = "australiaeast"

source "azure-arm" "windows-image" {
  # Basics authentication 
  subscription_id = var.subid
  tenant_id       = var.tenant

  # Image Settings
  os_type         = "Windows"
  image_publisher = "MicrosoftWindowsServer"
  image_offer     = "WindowsServer"
  image_sku       = "2016-Datacenter"

  # Temp location / config 
  location = var.location
  vm_size  = "Standard_D2_v2"
  # Created Image Name
  managed_image_name = var.capturenamename
  managed_image_resource_group_name = var.rgname

  # Communication (WinRM) and settings
  communicator      = "winrm"
  winrm_insecure    = "true"
  winrm_use_ssl     = "true"
  winrm_timeout     = "3m"
  winrm_username    = var.username
  winrm_password    = var.password

build {
  # Build the Image
  sources = [""]

  # Script for windows settings - powershell 
  provisioner "powershell" {
    script              = "Configuration.ps1"
    execution_policy    = "bypass"
    elevated_user       = var.username
    elevated_password   = var.password



write-output "Running User Data Script"
write-host "(host) Running User Data Script"

Set-ExecutionPolicy Unrestricted -Scope LocalMachine -Force -ErrorAction Ignore

# Don't set this before Set-ExecutionPolicy as it throws an error
$ErrorActionPreference = "stop"

# Remove HTTP listener
Remove-Item -Path WSMan:Localhostlistenerlistener* -Recurse

$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:LocalMachineMy -DnsName "packer"
New-Item -Path WSMan:LocalHostListener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force

# WinRM
write-output "Setting up WinRM"
write-host "(host) setting up WinRM"

cmd.exe /c winrm quickconfig -q
cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}'
cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}'
cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}'
cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}"
cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes
cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986"
cmd.exe /c net stop winrm
cmd.exe /c sc config winrm start= auto
cmd.exe /c net start winrm



subid = "b83ba8f2-XXXXXXXXXXXX-8ea3710e139aXX"
rgname = "DefaultResourceGroup"
capturenamename = "myimage"
location = "australiaeast"
username = "myadminusername"
password = "Password@thislocation"

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Toggle Dark Mode