#Provisioners
Provisioners run in order, top to bottom. If any step fails, the build fails.
| Type | Purpose |
|---|---|
shell | Run shell or PowerShell commands inside the VM |
file | Upload a file from files (or ConfigMap/Secret) to a path in the VM |
reboot | Reboot the VM and wait for it to come back |
windows-update | Install Windows Updates (loop with reboots until done) |
handbuild | Pause the build for manual intervention via VNC |
#shell
Runs commands over SSH. Each shell provisioner is a single script — variables and shell state do not carry across multiple shell steps. Use multi-line YAML blocks within one step if you need state to persist.
provisioners:
- name: install-packages
type: shell
shell:
inline: |
sudo apt-get update
sudo apt-get install -y nginx postgresql
- name: configure
type: shell
shell:
env:
APP_ENV: production
inline: |
echo "Configuring for $APP_ENV"
sudo systemctl enable nginx
Other shell fields:
scriptFrom— load the script from a ConfigMap or Secret instead of inlining it.executeCommand— wrap each command. Use{{ .Command }}as the placeholder. Common pattern for password-gated sudo:shell: executeCommand: "echo 'mypass' | sudo -S sh -c '{{ .Command }}'" inline: | apt-get install -y htopstepTimeout— caps this single step (e.g.,"30m").
For PowerShell (when communicator.shell: powershell), the same syntax applies:
provisioners:
- type: shell
shell:
inline: |
Write-Host "Hello"
Set-Service -Name BITS -StartupType Disabled
#file
Upload one file into the VM. Two ways to source the content:
# By reference to files (recommended)
- name: upload-cert
type: file
file:
fileRef: cert.pem
destination: /etc/ssl/certs/myca.pem
# By reference to a ConfigMap or Secret
- name: upload-config
type: file
file:
source:
configMapRef:
name: my-config
key: app.conf
destination: /etc/myapp/app.conf
Destinations for Windows must use Windows-style paths and double-escaped backslashes in YAML strings:
file:
fileRef: ruddergrade.exe
destination: "C:\\Windows\\system32\\ruddergrade.exe"
#reboot
Reboots and waits for SSH to come back. Use this any time you install kernel modules, change boot configuration, or want a clean state before the next step.
- name: reboot-after-drivers
type: reboot
The default reboot command is sudo reboot (bash) or shutdown /r /f /t 0 (PowerShell). Override with reboot.command if you need something different.
#windows-update
Loops Windows Update until no new updates are available, rebooting between cycles. Internally implements the same search/filter/install/reboot logic as packer-plugin-windows-update.
- name: install-updates
type: windows-update
windowsUpdate:
searchCriteria: 'BrowseOnly=0 and IsInstalled=0'
filters:
- "exclude:$_.Title -like '*Preview*'"
- 'include:$true'
updateLimit: 1000
searchCriteria is the Windows Update Agent search string. Common values:
| Criteria | Meaning |
|---|---|
"AutoSelectOnWebSites=1 and IsInstalled=0" | Important updates only |
"BrowseOnly=0 and IsInstalled=0" (default) | Recommended updates |
"IsInstalled=0" | Everything available |
filters are evaluated in order; first match wins. $_ is the IUpdate object. Allow-list pattern: explicit excludes followed by include:$true.
This step can take hours on a fresh Windows install. Set timeout accordingly.
#handbuild
Pauses the build so a human can drive the VM via VNC. The build resumes when a "continue" signal is sent. Useful for debugging a stuck install, capturing UI-only configuration, or one-off manual setup.
- name: manual-config
type: handbuild
handbuild:
instructions: 'Open Settings → Network → enable feature X, then send continue.'
While paused, attach to the VM's VNC console through the UI to interact with it directly.