diff --git a/ws2022/answer_files/Autounattend.xml.pkrtpl b/ws2022/answer_files/Autounattend.xml.pkrtpl
new file mode 100644
index 0000000..f39b646
--- /dev/null
+++ b/ws2022/answer_files/Autounattend.xml.pkrtpl
@@ -0,0 +1,346 @@
+
+
+
+
+
+
+
+
+
+
+ ${locale}
+
+ ${locale}
+ ${locale}
+ ${locale}
+ ${locale}
+
+
+
+
+
+
+ ${virtio_drive}:\vioscsi\2k22\amd64
+
+
+ ${virtio_drive}:\viostor\2k22\amd64
+
+
+ ${virtio_drive}:\NetKVM\2k22\amd64
+
+
+
+
+
+
+
+
+
+ 0
+ true
+
+
+ 1
+ EFI
+ 100
+
+
+ 2
+ MSR
+ 128
+
+
+ 3
+ Primary
+ true
+
+
+
+
+ 1
+ 1
+ FAT32
+
+
+
+ 2
+ 3
+ NTFS
+
+ C
+
+
+
+
+
+
+
+
+ 0
+ 3
+
+
+
+ /IMAGE/INDEX
+ ${image_index}
+
+
+
+
+
+
+ true
+
+ ${product_key}
+ Never
+
+
+
+
+
+
+
+
+
+
+
+
+ ${virtio_drive}:\vioscsi\2k22\amd64
+
+
+ ${virtio_drive}:\viostor\2k22\amd64
+
+
+ ${virtio_drive}:\NetKVM\2k22\amd64
+
+
+ ${virtio_drive}:\Balloon\2k22\amd64
+
+
+ ${virtio_drive}:\pvpanic\2k22\amd64
+
+
+ ${virtio_drive}:\qxldod\2k22\amd64
+
+
+ ${virtio_drive}:\vioserial\2k22\amd64
+
+
+ ${virtio_drive}:\vioinput\2k22\amd64
+
+
+ ${virtio_drive}:\viorng\2k22\amd64
+
+
+
+
+
+
+
+
+
+
+ *
+ ${timezone}
+
+
+
+ false
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+ ${admin_password}
+ true
+
+ true
+ Administrator
+
+
+
+
+ ${admin_password}
+ true
+
+
+
+
+
+ 1
+ cmd /c "${virtio_drive}:\virtio-win-guest-tools.exe /install /norestart -q"
+ Install VirtIO drivers and QEMU Guest Agent
+
+
+ 2
+ powershell -NoProfile -Command "Set-ExecutionPolicy Bypass -Scope LocalMachine -Force"
+ Set execution policy
+
+
+ 3
+ powershell -NoProfile -Command "Get-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory Private"
+ Set network to Private
+
+
+ 4
+ powershell -NoProfile -Command "Get-ChildItem WSMan:\localhost\Listener | Remove-Item -Recurse -ErrorAction SilentlyContinue"
+ Remove existing WinRM listeners
+
+
+ 5
+ powershell -NoProfile -Command "New-WSManInstance -ResourceURI winrm/config/Listener -SelectorSet @{Address='*';Transport='HTTP'}"
+ Create WinRM HTTP listener
+
+
+ 6
+ powershell -NoProfile -Command "Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value True"
+ Allow unencrypted WinRM
+
+
+ 7
+ powershell -NoProfile -Command "Set-Item WSMan:\localhost\Service\Auth\Basic -Value True"
+ Allow basic auth
+
+
+ 8
+ powershell -NoProfile -Command "Set-Item WSMan:\localhost\MaxEnvelopeSizekb -Value 8192"
+ Increase max envelope size
+
+
+ 9
+ powershell -NoProfile -Command "Set-Service WinRM -StartupType Automatic"
+ Set WinRM auto-start
+
+
+ 10
+ powershell -NoProfile -Command "New-NetFirewallRule -DisplayName WinRM-HTTP -Direction Inbound -Action Allow -Protocol TCP -LocalPort 5985 -Profile Any"
+ Open firewall port 5985
+
+
+ 11
+ powershell -NoProfile -Command "Restart-Service WinRM -Force"
+ Restart WinRM service
+
+
+ 12
+ powershell -NoProfile -Command "Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0"
+ Install OpenSSH Server
+
+
+ 13
+ powershell -NoProfile -Command "Set-Service sshd -StartupType Automatic; Start-Service sshd"
+ Enable and start sshd
+
+
+ 14
+ powershell -NoProfile -Command "New-NetFirewallRule -DisplayName OpenSSH-Server -Direction Inbound -Action Allow -Protocol TCP -LocalPort 22 -Profile Any"
+ Open firewall port 22
+
+
+ 15
+ powershell -NoProfile -Command "$conf = 'C:\ProgramData\ssh\sshd_config'; (Get-Content $conf) -replace '#PubkeyAuthentication yes','PubkeyAuthentication yes' -replace 'Match Group administrators','#Match Group administrators' -replace ' AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys','# AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys' | Set-Content $conf; Restart-Service sshd"
+ Configure sshd for pubkey auth
+
+
+
+
+ true
+ true
+ true
+ true
+ 3
+
+
+
+
+ ${locale}
+ ${locale}
+ ${locale}
+ ${locale}
+
+
+
+
diff --git a/ws2022/main.pkr.hcl b/ws2022/main.pkr.hcl
new file mode 100644
index 0000000..2d2bf2a
--- /dev/null
+++ b/ws2022/main.pkr.hcl
@@ -0,0 +1,115 @@
+packer {
+ required_plugins {
+ proxmox = {
+ version = "~> 1"
+ source = "github.com/hashicorp/proxmox"
+ }
+ windows-update = {
+ version = "0.17.3"
+ source = "github.com/rgl/windows-update"
+ }
+ }
+}
+
+# -----------------------------------------------------------------------------
+# Source: Proxmox VM definition
+# -----------------------------------------------------------------------------
+source "proxmox-iso" "ws2022" {
+ # Proxmox connection
+ proxmox_url = var.proxmox_url
+ username = var.proxmox_token_id
+ token = var.proxmox_token_secret
+ node = var.proxmox_node
+ insecure_skip_tls_verify = var.proxmox_skip_tls
+
+ # VM metadata
+ vm_name = var.vm_name
+ template_description = "Windows Server 2022 Datacenter - Cloudbase-Init - Built ${formatdate("YYYY-MM-DD", timestamp())}"
+ vm_id = var.vm_id
+
+ # Hardware
+ os = "win11"
+ memory = var.vm_memory
+ cores = var.vm_cores
+ cpu_type = "x86-64-v3"
+ machine = "pc-q35-10.1"
+ bios = "ovmf"
+ qemu_agent = true
+
+ efi_config {
+ efi_storage_pool = var.storage_pool
+ efi_type = "4m"
+ pre_enrolled_keys = true
+ }
+
+ scsi_controller = "virtio-scsi-single"
+
+ disks {
+ type = "scsi"
+ disk_size = var.disk_size
+ storage_pool = var.storage_pool
+ format = "raw"
+ }
+
+ network_adapters {
+ model = "virtio"
+ bridge = var.network_bridge
+ firewall = false
+ }
+
+ # Windows Server 2022 ISO
+ iso_file = var.iso_file
+
+ # --- KEY: dynamically generated ISO with templated Autounattend.xml ---
+ additional_iso_files {
+ cd_content = {
+ "Autounattend.xml" = templatefile("answer_files/Autounattend.xml.pkrtpl", {
+ admin_password = var.admin_password
+ image_index = var.image_index
+ product_key = var.product_key
+ locale = var.locale
+ timezone = var.timezone
+ virtio_drive = var.virtio_drive_letter
+ })
+ }
+ cd_label = "OEMDRV"
+ iso_storage_pool = var.iso_storage_pool
+ unmount = true
+ }
+
+ # VirtIO drivers ISO
+ additional_iso_files {
+ device = "sata1"
+ iso_file = var.virtio_iso
+ iso_storage_pool = var.iso_storage_pool
+ unmount = true
+ }
+
+ # WinRM communicator - password injected from variable
+ communicator = "winrm"
+ winrm_username = "Administrator"
+ winrm_password = var.admin_password
+ winrm_timeout = "90m"
+ winrm_insecure = true
+ winrm_use_ssl = false
+
+ boot_wait = "5s"
+ boot_command = [""]
+}
+
+# -----------------------------------------------------------------------------
+# Build: provisioning steps
+# -----------------------------------------------------------------------------
+build {
+ sources = ["source.proxmox-iso.ws2022"]
+
+ # Install and configure Cloudbase-Init
+ provisioner "powershell" {
+ script = "scripts/install-cloudbase-init.ps1"
+ }
+
+ # Sysprep with Cloudbase-Init's unattend
+ provisioner "powershell" {
+ script = "scripts/sysprep.ps1"
+ }
+}
diff --git a/ws2022/scripts/install-cloudbase-init.ps1 b/ws2022/scripts/install-cloudbase-init.ps1
new file mode 100644
index 0000000..968c0a9
--- /dev/null
+++ b/ws2022/scripts/install-cloudbase-init.ps1
@@ -0,0 +1,132 @@
+# install-cloudbase-init.ps1
+# Packer provisioner: downloads, installs and configures Cloudbase-Init
+# for Proxmox cloud-init (ConfigDrive metadata service).
+
+$msiUrl = "https://cloudbase.it/downloads/CloudbaseInitSetup_Stable_x64.msi"
+$msiPath = "C:\Windows\Temp\CloudbaseInitSetup.msi"
+$cbDir = "C:\Program Files\Cloudbase Solutions\Cloudbase-Init"
+
+# ---- Download ----
+Write-Host "Downloading Cloudbase-Init..."
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+
+$retries = 3
+for ($i = 1; $i -le $retries; $i++) {
+ try {
+ Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath -UseBasicParsing
+ break
+ } catch {
+ Write-Host "Download attempt $i failed: $_"
+ if ($i -eq $retries) { throw "Failed to download Cloudbase-Init after $retries attempts" }
+ Start-Sleep -Seconds 10
+ }
+}
+Unblock-File -Path $msiPath
+
+# ---- Install (silent, Local System account) ----
+Write-Host "Installing Cloudbase-Init..."
+$proc = Start-Process msiexec.exe -ArgumentList "/i `"$msiPath`" /qn /norestart /l*v C:\Windows\Temp\cloudbase-install.log RUN_SERVICE_AS_LOCAL_SYSTEM=1" -Wait -PassThru
+
+Write-Host "MSI exit code: $($proc.ExitCode)"
+if ($proc.ExitCode -ne 0) {
+ # Dump the MSI log on failure
+ if (Test-Path "C:\Windows\Temp\cloudbase-install.log") {
+ Get-Content "C:\Windows\Temp\cloudbase-install.log" | Select-Object -Last 50
+ }
+ throw "Cloudbase-Init MSI install failed with exit code $($proc.ExitCode)"
+}
+
+# Wait for MSI to finish writing files
+Start-Sleep -Seconds 15
+
+# ---- Verify installation ----
+Write-Host "Verifying Cloudbase-Init installation..."
+
+# Check the service exists
+$svc = Get-Service -Name "cloudbase-init" -ErrorAction SilentlyContinue
+if (-not $svc) {
+ Write-Host "Service not found. Listing directory..."
+ if (Test-Path $cbDir) {
+ Get-ChildItem $cbDir -Recurse -Depth 2 | Select-Object FullName
+ } else {
+ Write-Host "$cbDir does not exist!"
+ }
+ throw "Cloudbase-Init service not found after install!"
+}
+
+Write-Host "Cloudbase-Init installed. Service status: $($svc.Status)"
+Write-Host "Cloudbase-Init installed successfully."
+
+# ---- cloudbase-init.conf (main service - runs on normal boot after sysprep) ----
+$mainConf = @"
+[DEFAULT]
+username=Administrator
+groups=Administrators
+inject_user_password=true
+config_drive_raw_hhd=true
+config_drive_cdrom=true
+config_drive_vfat=true
+bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe
+mtools_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\
+verbose=true
+debug=true
+log_dir=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\log\
+log_file=cloudbase-init.log
+default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN,requests=WARN
+logging_serial_port_settings=
+first_logon_behaviour=no
+mtu_use_dhcp_config=true
+ntp_use_dhcp_config=true
+local_scripts_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\
+check_latest_version=false
+plugins=cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin,
+ cloudbaseinit.plugins.common.networkconfig.NetworkConfigPlugin,
+ cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin,
+ cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin
+metadata_services=cloudbaseinit.metadata.services.configdrive.ConfigDriveService
+"@
+
+Write-Host "Writing cloudbase-init.conf..."
+Set-Content -Path "$cbDir\conf\cloudbase-init.conf" -Value $mainConf -Encoding ASCII
+
+# ---- cloudbase-init-unattend.conf (specialize phase on first boot after sysprep) ----
+$unattendConf = @"
+[DEFAULT]
+username=Administrator
+groups=Administrators
+inject_user_password=false
+config_drive_raw_hhd=true
+config_drive_cdrom=true
+config_drive_vfat=true
+bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe
+mtools_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\
+verbose=true
+debug=true
+log_dir=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\log\
+log_file=cloudbase-init-unattend.log
+default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN,requests=WARN
+logging_serial_port_settings=
+mtu_use_dhcp_config=false
+ntp_use_dhcp_config=false
+first_logon_behaviour=no
+local_scripts_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\
+check_latest_version=false
+plugins=cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin,
+ cloudbaseinit.plugins.common.networkconfig.NetworkConfigPlugin,
+ cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin
+metadata_services=cloudbaseinit.metadata.services.configdrive.ConfigDriveService
+allow_reboot=true
+stop_service_on_exit=false
+"@
+
+Write-Host "Writing cloudbase-init-unattend.conf..."
+Set-Content -Path "$cbDir\conf\cloudbase-init-unattend.conf" -Value $unattendConf -Encoding ASCII
+
+# ---- Service configuration ----
+Write-Host "Configuring Cloudbase-Init service..."
+Set-Service -Name "cloudbase-init" -StartupType Automatic
+
+# ---- Cleanup ----
+Remove-Item $msiPath -Force -ErrorAction SilentlyContinue
+
+Write-Host "=== Cloudbase-Init setup complete ==="
diff --git a/ws2022/scripts/sysprep.ps1 b/ws2022/scripts/sysprep.ps1
new file mode 100644
index 0000000..f239d5b
--- /dev/null
+++ b/ws2022/scripts/sysprep.ps1
@@ -0,0 +1,24 @@
+$ErrorActionPreference = "Stop"
+
+$cbUnattend = "C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf\Unattend.xml"
+
+if (-not (Test-Path $cbUnattend)) {
+ throw "Cloudbase-Init Unattend.xml not found at: $cbUnattend"
+}
+
+Write-Host "Removing Packer WinRM firewall rule..."
+Remove-NetFirewallRule -DisplayName "WinRM HTTP" -ErrorAction SilentlyContinue
+
+Write-Host "Cleaning temp files..."
+Remove-Item -Path "C:\Windows\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue
+
+Write-Host "Enabling built-in Administrator account..."
+net user Administrator /active:yes
+net user Administrator /logonpasswordchg:no
+
+Write-Host "Running Sysprep /generalize /oobe /shutdown..."
+& "$env:SystemRoot\System32\Sysprep\Sysprep.exe" `
+ /generalize `
+ /oobe `
+ /shutdown `
+ /unattend:"$cbUnattend"
diff --git a/ws2022/variables.pkr.hcl b/ws2022/variables.pkr.hcl
new file mode 100644
index 0000000..921d3cf
--- /dev/null
+++ b/ws2022/variables.pkr.hcl
@@ -0,0 +1,116 @@
+variable "proxmox_url" {
+ type = string
+ description = "Proxmox API URL (e.g. https://pve.example.com:8006/api2/json)"
+}
+
+variable "proxmox_token_id" {
+ type = string
+ sensitive = true
+ description = "Proxmox API token ID (e.g. user@pam!packer)"
+}
+
+variable "proxmox_token_secret" {
+ type = string
+ sensitive = true
+ description = "Proxmox API token secret"
+}
+
+variable "proxmox_node" {
+ type = string
+ description = "Proxmox node name to build on"
+}
+
+variable "proxmox_skip_tls" {
+ type = bool
+ default = true
+}
+
+variable "vm_name" {
+ type = string
+ default = "ws2022dc-template"
+}
+
+variable "vm_id" {
+ type = number
+ default = 1002
+}
+
+variable "vm_memory" {
+ type = number
+ default = 4096
+}
+
+variable "vm_cores" {
+ type = number
+ default = 2
+}
+
+variable "disk_size" {
+ type = string
+ default = "60G"
+}
+
+variable "network_bridge" {
+ type = string
+ default = "vmbr0"
+}
+
+variable "storage_pool" {
+ type = string
+ default = "local-lvm"
+ description = "Proxmox storage pool for VM disks and EFI"
+}
+
+variable "iso_storage_pool" {
+ type = string
+ default = "local"
+ description = "Proxmox storage pool where ISOs live and generated ISOs are placed"
+}
+
+variable "iso_file" {
+ type = string
+ description = "Path to Windows Server 2022 ISO in Proxmox (e.g. local:iso/WindowsServer2022.iso)"
+ default = "local-btrfs:iso/en-us_windows_server_2022_updated_july_2023_x64_dvd_541692c3.iso"
+}
+
+variable "virtio_iso" {
+ type = string
+ default = "local-btrfs:iso/virtio-win-0.1.285.iso"
+ description = "Path to VirtIO drivers ISO in Proxmox"
+}
+
+variable "virtio_drive_letter" {
+ type = string
+ default = "E"
+ description = "Drive letter where the VirtIO ISO is mounted inside Windows"
+}
+
+variable "admin_password" {
+ type = string
+ sensitive = true
+ description = "Administrator password used during build (will be cleared by sysprep)"
+}
+
+variable "image_index" {
+ type = string
+ default = "4"
+ description = "Windows image index from eval ISO: 1=Std Core, 2=Std Desktop, 3=DC Core, 4=DC Desktop (verify with dism /Get-ImageInfo)"
+}
+
+variable "product_key" {
+ type = string
+ default = "WX4NM-KYWYW-QJJR4-XV3QB-6VM33"
+ description = "KMS GVLK for Windows Server 2022 Datacenter"
+}
+
+variable "locale" {
+ type = string
+ default = "en-US"
+ description = "Windows locale for UI, input, system (e.g. en-US, hr-HR)"
+}
+
+variable "timezone" {
+ type = string
+ default = "Central European Standard Time"
+ description = "Windows timezone name"
+}