diff --git a/ansible/roles/base/tasks/main.yml b/ansible/roles/base/tasks/main.yml
index ba19a60..d486600 100644
--- a/ansible/roles/base/tasks/main.yml
+++ b/ansible/roles/base/tasks/main.yml
@@ -20,4 +20,6 @@
include_tasks: suse.yml
when: "ansible_facts['distribution'] in ['openSUSE Leap', 'Suse']"
-...
\ No newline at end of file
+- name: "{{ base_task_name }}"
+ ansible.builtin.include_tasks: windows.yml
+ when: ansible_os_family == "Windows"
diff --git a/ansible/roles/base/tasks/windows.yml b/ansible/roles/base/tasks/windows.yml
new file mode 100644
index 0000000..d4559dc
--- /dev/null
+++ b/ansible/roles/base/tasks/windows.yml
@@ -0,0 +1,51 @@
+---
+# Microsoft Windows specific tasks.
+
+# Tasks for updating the operating system and installing additional packages.
+- name: Getting guest operating system information
+ ansible.builtin.debug:
+ msg: "OS: {{ ansible_os_name }}"
+
+- name: Ensure .NET Framework 4.8 requirement is satisfied for Chocolatey v2.0.0 and later
+ when: ansible_os_installation_type != "Server Core"
+ block:
+ - name: Install Chocolatey CLI
+ chocolatey.chocolatey.win_chocolatey:
+ name: chocolatey
+ state: present
+ version: 1.4.0
+
+ - name: Install Microsoft .NET Framework 4.8
+ chocolatey.chocolatey.win_chocolatey:
+ name: netfx-4.8
+ state: present
+
+ - name: Reboot the host to complete .NET Framework 4.8 install
+ ansible.windows.win_reboot:
+
+ - name: Install latest version of Chocolatey
+ chocolatey.chocolatey.win_chocolatey:
+ name: chocolatey
+ state: latest
+
+ - name: Installing additional packages using Chocolatey
+ chocolatey.chocolatey.win_chocolatey:
+ name:
+ - googlechrome
+ - putty
+ state: latest
+ ignore_checksums: true
+
+- name: Updating the operating system
+ ansible.windows.win_updates:
+ category_names:
+ - SecurityUpdates
+ - CriticalUpdates
+ reject_list:
+ - 5034439
+ - 5034441
+ reboot: true
+ register: win_updates
+ until: not win_updates.failed
+ retries: 5
+ delay: 300
diff --git a/ansible/roles/configure/tasks/main.yml b/ansible/roles/configure/tasks/main.yml
index b295b54..dd5683e 100644
--- a/ansible/roles/configure/tasks/main.yml
+++ b/ansible/roles/configure/tasks/main.yml
@@ -16,4 +16,6 @@
include_tasks: suse.yml
when: "ansible_facts['distribution'] in ['openSUSE Leap', 'Suse']"
-...
\ No newline at end of file
+- name: "{{ configure_task_name }}"
+ ansible.builtin.include_tasks: windows.yml
+ when: ansible_os_family == "Windows"
diff --git a/ansible/roles/configure/tasks/windows.yml b/ansible/roles/configure/tasks/windows.yml
new file mode 100644
index 0000000..353f110
--- /dev/null
+++ b/ansible/roles/configure/tasks/windows.yml
@@ -0,0 +1,133 @@
+---
+# Microsoft Windows specific tasks.
+
+# Set the Windows Explorer options.
+# ansible-lint: disable=line-length
+- name: Setting the Windows Explorer options...
+ when: ansible_os_installation_type != "Server Core"
+ block:
+ - name: Show hidden files.
+ ansible.windows.win_regedit:
+ path: HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
+ name: Hidden
+ data: 1
+ type: dword
+
+ - name: Show file extensions.
+ ansible.windows.win_regedit:
+ path: HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
+ name: HideFileExt
+ data: 0
+ type: dword
+
+ - name: Show drives with no media.
+ ansible.windows.win_regedit:
+ path: HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
+ name: HideDrivesWithNoMedia
+ data: 0
+ type: dword
+
+ - name: Disabling Sync Provider Notifications.
+ ansible.windows.win_regedit:
+ path: HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
+ name: ShowSyncProviderNotifications
+ data: 1
+ type: dword
+
+# Disable system hibernation.
+- name: Disabling System Hibernation...
+ block:
+ - name: Disabling Hibernation.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\Power
+ name: HibernateEnabled
+ data: 0
+ type: dword
+
+ - name: Setting HiberFileSizePercent to 0.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\Power
+ name: HiberFileSizePercent
+ data: 0
+ type: dword
+
+# Disable TLS 1.0.s
+- name: Disabling TLS 1.0 for Client...
+ block:
+ - name: Disabling TLS 1.0 for Client.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client
+ name: Enabled
+ data: 0
+ type: dword
+
+ - name: Setting TLS 1.0 for Client to Disabled by Default.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client
+ name: DisabledByDefault
+ data: 1
+ type: dword
+
+ - name: Disabling TLS 1.0 for Server.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server
+ name: Enabled
+ data: 0
+ type: dword
+
+ - name: Setting TLS 1.0 for Server to Disabled by Default.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server
+ name: DisabledByDefault
+ data: 1
+ type: dword
+
+# Disable TLS 1.1.
+- name: Disabling TLS 1.1 for Client...
+ block:
+ - name: Disabling TLS 1.1 for Client.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client
+ name: Enabled
+ data: 0
+ type: dword
+
+ - name: Setting TLS 1.1 for Client to Disabled by Default.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client
+ name: DisabledByDefault
+ data: 1
+ type: dword
+
+ - name: Disabling TLS 1.1 for Server.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server
+ name: Enabled
+ data: 0
+ type: dword
+
+ - name: Setting TLS 1.1 for Server to Disabled by Default.
+ ansible.windows.win_regedit:
+ path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server
+ name: DisabledByDefault
+ data: 1
+ type: dword
+
+# Disable Password Expiration for Administrator and Build Accounts
+- name: Disabling Local Administrator Password Expiration...
+ ansible.windows.win_user:
+ name: Administrator
+ password_never_expires: true
+
+- name: Disabling Password Expiration for "{{ build_username }}"
+ ansible.windows.win_user:
+ name: "{{ build_username }}"
+ password_never_expires: true
+
+# Enable Remote Desktop.
+- name: Enabling Remote Desktop...
+ ansible.windows.win_powershell:
+ script: |
+ Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name "fDenyTSConnections" -Value 0 | Out-Null
+ Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name "UserAuthentication" -Value 0
+ Enable-NetFirewallRule -Group '@FirewallAPI.dll,-28752'
diff --git a/ansible/windows-playbook.yml b/ansible/windows-playbook.yml
new file mode 100644
index 0000000..3cfb776
--- /dev/null
+++ b/ansible/windows-playbook.yml
@@ -0,0 +1,8 @@
+---
+- name: Playbook for Microsoft Windows
+ debugger: never
+ gather_facts: true
+ hosts: all
+ roles:
+ - base
+ - configure
diff --git a/ansible/windows-requirements.yml b/ansible/windows-requirements.yml
new file mode 100644
index 0000000..d6b35fd
--- /dev/null
+++ b/ansible/windows-requirements.yml
@@ -0,0 +1,8 @@
+---
+collections:
+ - name: ansible.windows
+ version: 2.3.0
+ - name: chocolatey.chocolatey
+ version: 1.5.1
+ - name: community.general
+ version: 8.6.0
diff --git a/builds/proxy.pkrvars.hcl.example b/builds/proxy.pkrvars.hcl.example
new file mode 100644
index 0000000..6765d05
--- /dev/null
+++ b/builds/proxy.pkrvars.hcl.example
@@ -0,0 +1,11 @@
+/*
+ DESCRIPTION:
+ Proxy variables used for Linux builds. (Optional)
+ - Variables are passed to and used by configuration scripts.
+*/
+
+// Proxy Credentials
+// communicator_proxy_host = "proxy.example.com"
+// communicator_proxy_port = 3128
+// communicator_proxy_username = "packer_proxy"
+// communicator_proxy_password = "Sup3rdup3rSecr3t!"
diff --git a/builds/windows/desktop/11/data/autounattend.pkrtpl.hcl b/builds/windows/desktop/11/data/autounattend.pkrtpl.hcl
new file mode 100644
index 0000000..26a5260
--- /dev/null
+++ b/builds/windows/desktop/11/data/autounattend.pkrtpl.hcl
@@ -0,0 +1,220 @@
+
+
+
+
+
+ ${vm_inst_os_language}
+
+ ${vm_inst_os_keyboard}
+ ${vm_inst_os_language}
+ ${vm_inst_os_language}
+ ${vm_inst_os_language}
+ ${vm_inst_os_language}
+
+
+
+
+ F:\viostor\w11\amd64\
+
+
+ F:\NetKVM\w11\amd64\
+
+
+
+
+
+
+ 0
+ true
+
+
+
+ 1
+ Primary
+ 550
+
+
+
+ 2
+ EFI
+ 100
+
+
+
+ 3
+ MSR
+ 128
+
+
+
+ 4
+ Primary
+ true
+
+
+
+
+
+ 1
+ 1
+
+ NTFS
+ DE94BBA4-06D1-4D40-A16A-BFD50179D6AC
+
+
+
+ 2
+ 2
+
+ FAT32
+
+
+
+ 3
+ 3
+
+
+
+ 4
+ 4
+
+ C
+ NTFS
+
+
+
+
+
+
+
+
+ /IMAGE/NAME
+ ${vm_inst_os_image}
+
+
+
+ 0
+ 4
+
+
+
+
+
+ 1
+
+ cmd /c powercfg.exe /s 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
+
+
+
+ true
+ ${build_username}
+ ${build_username}
+ %{if vm_inst_os_eval != true ~}
+
+ ${vm_inst_os_key}
+ OnError
+
+ %{ endif ~}
+
+ false
+
+
+
+
+ false
+
+
+
+
+ 1
+
+
+
+
+
+ false
+
+ ${vm_guest_os_timezone}
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+ ${vm_guest_os_keyboard}
+ ${vm_guest_os_language}
+ ${vm_guest_os_language}
+ ${vm_guest_os_language}
+ ${vm_guest_os_language}
+
+
+
+
+ ${build_password}
+ true
+
+ true
+ ${build_username}
+
+
+ true
+ true
+ true
+ true
+ true
+ Work
+ 2
+
+
+
+ ${build_password}
+ true
+
+
+
+
+ ${build_password}
+ true
+
+ administrators
+ ${build_username}
+ ${build_username}
+ Build Account
+
+
+
+
+
+ %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
+ Set Execution Policy 64-Bit
+ 1
+ true
+
+
+ %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
+ Set Execution Policy 32-Bit
+ 2
+ true
+
+
+ %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -File E:\windows-virtio.ps1
+ 3
+ Install VMware Tools
+
+
+ %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -File E:\windows-init.ps1
+ 4
+ Initial Configuration
+
+
+
+
+
diff --git a/builds/windows/desktop/11/variables.pkr.hcl b/builds/windows/desktop/11/variables.pkr.hcl
new file mode 100644
index 0000000..8169e6d
--- /dev/null
+++ b/builds/windows/desktop/11/variables.pkr.hcl
@@ -0,0 +1,413 @@
+/*
+ DESCRIPTION:
+ Microsoft Windows 11 input variables.
+ Packer Plugin for Proxmox: 'proxmox-iso' builder.
+*/
+
+// BLOCK: variable
+// Defines the input variables.
+
+// Proxmox Credentials
+
+variable "proxmox_hostname" {
+ type = string
+ description = "The FQDN or IP address of a Proxmox node. Only one node should be specified in a cluster."
+}
+
+variable "proxmox_api_token_id" {
+ type = string
+ description = "The token to login to the Proxmox node/cluster. The format is USER@REALM!TOKENID. (e.g. packer@pam!packer_pve_token)"
+}
+
+variable "proxmox_api_token_secret" {
+ type = string
+ description = "The secret for the API token used to login to the Proxmox API."
+# sensitive = true
+}
+
+variable "proxmox_insecure_connection" {
+ description = "true/false to skip Proxmox TLS certificate checks."
+ type = bool
+ default = true
+}
+
+// Proxmox Settings
+
+variable "proxmox_node" {
+ type = string
+ description = "The name of the Proxmox node that Packer will build templates on."
+}
+
+// Installer Settings
+
+variable "vm_inst_os_language" {
+ type = string
+ description = "The installation operating system lanugage."
+ default = "en-US"
+}
+
+variable "vm_inst_os_keyboard" {
+ type = string
+ description = "The installation operating system keyboard input."
+ default = "en-US"
+}
+
+variable "vm_inst_os_eval" {
+ type = bool
+ description = "Build using the operating system evaluation"
+ default = true
+}
+
+variable "vm_inst_os_image_pro" {
+ type = string
+ description = "The installation operating system image input.\nDoes not support evaluation."
+ default = "Windows 11 Pro"
+}
+
+variable "vm_inst_os_image_ent" {
+ type = string
+ description = "The installation operating system image input. Does support evaluation."
+ default = "Windows 11 Enterprise"
+}
+
+variable "vm_inst_os_key_pro" {
+ type = string
+ description = "The installation operating system key input."
+}
+variable "vm_inst_os_key_ent" {
+ type = string
+ description = "The installation operating system key input."
+}
+
+// Virtual Machine Settings
+
+variable "vm_os_language" {
+ type = string
+ description = "The guest operating system lanugage."
+ default = "en-US"
+}
+
+variable "vm_os_keyboard" {
+ type = string
+ description = "The guest operating system keyboard input."
+ default = "en-US"
+}
+
+variable "vm_os_timezone" {
+ type = string
+ description = "The guest operating system timezone."
+ default = "UTC"
+}
+
+variable "vm_os_family" {
+ type = string
+ description = "The guest operating system family. Used for naming. (e.g. 'linux')"
+ default = "windows"
+}
+
+variable "vm_os_name" {
+ type = string
+ description = "The guest operating system name. Used for naming."
+ default = "desktop"
+}
+
+variable "vm_os_version" {
+ type = string
+ description = "The guest operating system version. Used for naming."
+ default = "11"
+}
+
+variable "vm_os_edition_pro" {
+ type = string
+ description = "The guest operating system edition. Used for naming."
+ default = "pro"
+}
+
+variable "vm_os_edition_ent" {
+ type = string
+ description = "The guest operating system edition. Used for naming."
+ default = "ent"
+}
+
+variable "vm_os_type" {
+ type = string
+ description = "The guest operating system type, also know as guestid."
+}
+
+variable "vm_bios" {
+ type = string
+ description = "The firmware type. Allowed values 'ovmf' or 'seabios'"
+ default = "ovmf"
+ validation {
+ condition = contains(["ovmf", "seabios"], var.vm_bios)
+ error_message = "The vm_bios value must be 'ovmf' or 'seabios'."
+ }
+}
+
+variable "vm_firmware_path" {
+ type = string
+ description = "The firmware file to be used. Needed for EFI"
+ default = "/usr/share/ovmf/OVMF.fd"
+}
+
+variable "vm_efi_storage_pool" {
+ type = string
+ description = "Set the UEFI disk storage location. (e.g. 'local')"
+ default = "local"
+}
+
+variable "vm_efi_type" {
+ type = string
+ description = "Specifies the version of the OVMF firmware to be used. (e.g. '4m')"
+ default = "4m"
+}
+
+variable "vm_efi_pre_enrolled_keys" {
+ type = bool
+ description = "Whether Microsoft Standard Secure Boot keys should be pre-loaded on the EFI disk. (e.g. false)"
+ default = false
+}
+
+variable "vm_machine_type" {
+ type = string
+ description = "Set the machine type. Supported values are 'pc' or 'q35'."
+ default = "pc"
+ validation {
+ condition = contains(["pc", "q35"], var.vm_machine_type)
+ error_message = "The vm_machine_type value must be 'pc' or 'q35'."
+ }
+}
+variable "vm_cpu_count" {
+ type = number
+ description = "The number of virtual CPUs."
+ default = 2
+}
+
+variable "vm_cpu_sockets" {
+ type = number
+ description = "The number of virtual CPU sockets. (e.g. '1')"
+}
+
+variable "vm_cpu_type" {
+ type = string
+ description = "The CPU type to emulate. See the Proxmox API documentation for the complete list of accepted values. For best performance, set this to host. Defaults to kvm64."
+}
+
+variable "vm_mem_size" {
+ type = number
+ description = "The size for the virtual memory in MB."
+ default = 4096
+}
+
+variable "vm_tpm_storage_pool" {
+ type = string
+ description = "Storage location virtual trusted platform module (vTPM)."
+}
+
+variable "vm_tpm_version" {
+ type = string
+ description = "Version of virtual trusted platform module (vTPM). Can be 'v1.2' or 'v2.0' Defaults to 'v2.0'"
+ default = "v2.0"
+}
+
+variable "vm_disk_controller_type" {
+ type = string
+ description = "The SCSI controller model to emulate. (e.g. 'virtio-scsi-pci')"
+}
+
+variable "vm_disk_type" {
+ type = string
+ description = "The type of disk to emulate. (e.g. 'virtio')"
+}
+
+variable "vm_storage_pool" {
+ type = string
+ description = "The name of the Proxmox storage pool to store the VM template. (e.g. 'local')"
+}
+
+variable "vm_disk_size" {
+ type = string
+ description = "The size for the virtual disk in GB. (e.g. '32G')"
+}
+
+variable "vm_disk_format" {
+ type = string
+ description = "The format of the file backing the disk. (e.g. 'qcow2')"
+}
+
+variable "vm_network_card_model" {
+ type = string
+ description = "The model of the virtual network adapter to emulate. (e.g. 'virtio')"
+}
+
+variable "vm_bridge_interface" {
+ type = string
+ description = "The name of the Proxmox bridge to attach the adapter to."
+}
+
+variable "vm_vlan_tag" {
+ type = string
+ description = "If the adapter should tag packets, give the VLAN ID. (e.g. '102')"
+}
+
+variable "vm_video_ram" {
+ type = number
+ description = "The size for the video memory in KB."
+ default = 4096
+}
+
+variable "vm_video_displays" {
+ type = number
+ description = "The number of video displays."
+ default = 1
+}
+
+// Removable Media Settings
+
+variable "common_iso_storage" {
+ type = string
+ description = "The name of the source Proxmox storage location for ISO images. (e.g. 'local')"
+}
+
+variable "iso_path" {
+ type = string
+ description = "The path on the source Proxmox storage location for ISO images. (e.g. 'iso')"
+}
+
+variable "iso_file" {
+ type = string
+ description = "The file name of the ISO image used by the vendor. (e.g. 'ubuntu--live-server-amd64.iso')"
+}
+
+variable "iso_checksum" {
+ type = string
+ description = "The checksum value of the ISO image provided by the vendor."
+}
+
+// Boot Settings
+
+variable "common_data_source" {
+ type = string
+ description = "The provisioning data source. One of `http` or `disk`."
+}
+
+variable "common_http_bind_address" {
+ type = string
+ description = "Define an IP address on the host to use for the HTTP server."
+ default = null
+}
+
+variable "common_http_port_min" {
+ type = number
+ description = "The start of the HTTP port range."
+}
+
+variable "common_http_port_max" {
+ type = number
+ description = "The end of the HTTP port range."
+}
+
+// variable "vm_boot_order" {
+// type = string
+// description = "The boot order for virtual machines devices."
+// }
+
+variable "vm_boot_wait" {
+ type = string
+ description = "The time to wait before boot."
+ default = "5s"
+}
+
+variable "vm_boot_command" {
+ type = list(string)
+ description = "The virtual machine boot command."
+ default = [""]
+}
+
+variable "common_ip_wait_timeout" {
+ type = string
+ description = "Time to wait for guest operating system IP address response."
+}
+
+variable "common_shutdown_timeout" {
+ type = string
+ description = "Time to wait for guest operating system shutdown."
+}
+
+// Communicator Settings and Credentials
+
+variable "build_username" {
+ type = string
+ description = "The username to login to the guest operating system."
+ sensitive = true
+}
+
+variable "build_password" {
+ type = string
+ description = "The password to login to the guest operating system."
+ sensitive = true
+}
+
+variable "build_password_encrypted" {
+ type = string
+ description = "The SHA-512 encrypted password to login to the guest operating system."
+ sensitive = true
+ default = ""
+}
+
+variable "build_key" {
+ type = string
+ description = "The public key to login to the guest operating system."
+ sensitive = true
+ default = ""
+}
+
+// Communicator Credentials
+
+variable "communicator_port" {
+ type = number
+ description = "The port for the communicator protocol."
+ default = 5985
+}
+
+variable "communicator_timeout" {
+ type = string
+ description = "The timeout for the communicator protocol."
+ default = "12h"
+}
+
+// Ansible Credentials
+
+variable "ansible_username" {
+ type = string
+ description = "The username for Ansible to login to the guest operating system."
+ sensitive = true
+}
+
+variable "ansible_key" {
+ type = string
+ description = "The public key for Ansible to login to the guest operating system."
+ sensitive = true
+}
+
+// Provisioner Settings
+
+variable "scripts" {
+ type = list(string)
+ description = "A list of scripts and their relative paths to transfer and run."
+ default = []
+}
+
+variable "inline" {
+ type = list(string)
+ description = "A list of commands to run."
+ default = []
+}
+
+// HCP Packer Settings
+
+variable "common_hcp_packer_registry_enabled" {
+ type = bool
+ description = "Enable the HCP Packer registry."
+ default = false
+}
diff --git a/builds/windows/desktop/11/windows.auto.pkrvars.hcl b/builds/windows/desktop/11/windows.auto.pkrvars.hcl
new file mode 100644
index 0000000..c38a40a
--- /dev/null
+++ b/builds/windows/desktop/11/windows.auto.pkrvars.hcl
@@ -0,0 +1,43 @@
+/*
+ DESCRIPTION:
+ Microsoft Windows 11 variables used by the Packer Plugin for Proxmox (proxmox-iso).
+*/
+
+// Guest Operating System Metadata
+vm_os_language = "en_US"
+vm_os_keyboard = "us"
+vm_os_timezone = "UTC"
+
+// Virtual Machine Guest Operating System Setting
+vm_os_type = "win11"
+
+// Machine type
+// Q35 less resource overhead and newer chipset
+vm_machine_type = "q35"
+
+// Virtual Machine Hardware Settings
+vm_bios = "ovmf"
+vm_cpu_count = 2
+vm_cpu_sockets = 1
+vm_cpu_type = "x86-64-v2-AES"
+vm_mem_size = 4096
+vm_disk_type = "virtio"
+vm_disk_size = "32G"
+vm_disk_format = "raw"
+vm_disk_controller_type = "virtio-scsi-single"
+vm_network_card_model = "virtio"
+
+// Removable Media Settings
+iso_path = "iso"
+iso_file = "22631.2428.231001-0608.23H2_NI_RELEASE_SVC_REFRESH_CLIENTENTERPRISEEVAL_OEMRET_x64FRE_en-us.iso"
+iso_checksum = ""
+
+// Boot Settings
+vm_boot_order = "order=virtio0;ide2;net0"
+
+// EFI Settings
+vm_efi_storage_pool = "pool0"
+vm_firmware_path = "./OVMF.fd"
+
+// TPM Settings
+vm_tpm_storage_pool = "pool0"
diff --git a/builds/windows/desktop/11/windows.pkr.hcl b/builds/windows/desktop/11/windows.pkr.hcl
new file mode 100644
index 0000000..0295da7
--- /dev/null
+++ b/builds/windows/desktop/11/windows.pkr.hcl
@@ -0,0 +1,317 @@
+/*
+ DESCRIPTION:
+ Microsoft Windows 11 build definition.
+ Packer Plugin for Proxmox: 'proxmox-iso' builder.
+*/
+
+// BLOCK: packer
+// The Packer configuration.
+
+packer {
+ required_version = ">= 1.11.0"
+ required_plugins {
+ ansible = {
+ source = "github.com/hashicorp/ansible"
+ version = "~> 1"
+ }
+ git = {
+ version = ">= 0.6.2"
+ source = "github.com/ethanmdavidson/git"
+ }
+ proxmox = {
+ version = ">= 1.2.2"
+ source = "github.com/hashicorp/proxmox"
+ }
+ }
+}
+
+// BLOCK: data
+// Defines the data sources.
+
+data "git-repository" "cwd" {}
+
+// BLOCK: locals
+// Defines the local variables.
+
+locals {
+ build_by = "Built by: HashiCorp Packer ${packer.version}"
+ build_date = formatdate("YYYY-MM-DD hh:mm ZZZ", timestamp())
+ build_version = data.git-repository.cwd.head
+ build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}"
+ manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
+ manifest_path = "${path.cwd}/manifests/"
+ manifest_output = "${local.manifest_path}${local.manifest_date}.json"
+ vm_name_pro = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}-${var.vm_os_edition_pro}"
+ vm_name_ent = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}-${var.vm_os_edition_ent}"
+ bucket_name = replace("${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}", ".", "")
+ bucket_description = "${var.vm_os_family} ${var.vm_os_name} ${var.vm_os_version}"
+}
+
+// BLOCK: source
+// Defines the builder configuration blocks.
+
+source "proxmox-iso" "windows-desktop-pro" {
+
+ // Proxmox Connection Settings and Credentials
+ proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
+ username = var.proxmox_api_token_id
+ token = var.proxmox_api_token_secret
+ insecure_skip_tls_verify = var.proxmox_insecure_connection
+
+ // Proxmox Settings
+ node = var.proxmox_node
+
+ // Virtual Machine Settings
+ machine = var.vm_machine_type
+ vm_name = local.vm_name_pro
+ bios = var.vm_bios
+ sockets = var.vm_cpu_sockets
+ cores = var.vm_cpu_count
+ cpu_type = var.vm_cpu_type
+ memory = var.vm_mem_size
+ os = var.vm_os_type
+ qemu_agent = true
+ scsi_controller = var.vm_disk_controller_type
+
+ disks {
+ disk_size = var.vm_disk_size
+ type = var.vm_disk_type
+ storage_pool = var.vm_storage_pool
+ format = var.vm_disk_format
+ }
+
+ network_adapters {
+ bridge = var.vm_bridge_interface
+ model = var.vm_network_card_model
+ vlan_tag = var.vm_vlan_tag
+ }
+
+ tpm_config {
+ tpm_storage_pool = var.vm_tpm_storage_pool
+ tpm_version = var.vm_tpm_version
+ }
+
+ dynamic "efi_config" {
+ for_each = var.vm_bios == "ovmf" ? [1] : []
+ content {
+ efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
+ efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
+ pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
+ }
+ }
+
+ # Windows Server ISO File
+ boot_iso {
+ iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
+ unmount = true
+ iso_checksum = var.iso_checksum
+ type = "ide"
+ index = 0
+ }
+
+ // Removable Media Settings
+ additional_iso_files {
+ iso_file = "${var.common_iso_storage}:iso/virtio-win.iso"
+ iso_storage_pool = var.common_iso_storage
+ cd_label = "VirtIO"
+ unmount = true
+ }
+
+ additional_iso_files {
+ cd_files = [
+ "${path.cwd}/scripts/${var.vm_os_family}/"
+ ]
+ cd_content = {
+ "autounattend.xml" = templatefile("${abspath(path.root)}/data/autounattend.pkrtpl.hcl", {
+ build_username = var.build_username
+ build_password = var.build_password
+ vm_inst_os_eval = var.vm_inst_os_eval // Does not support evaluation.
+ vm_inst_os_language = var.vm_inst_os_language
+ vm_inst_os_keyboard = var.vm_inst_os_keyboard
+ vm_inst_os_image = var.vm_inst_os_image_pro
+ vm_inst_os_key = var.vm_inst_os_key_pro // Does not support evaluation.
+ vm_guest_os_language = var.vm_os_language
+ vm_guest_os_keyboard = var.vm_os_keyboard
+ vm_guest_os_timezone = var.vm_os_timezone
+ })
+ }
+ cd_label = "Unattend"
+ iso_storage_pool = var.common_iso_storage
+ unmount = true
+ }
+
+ // Boot and Provisioning Settings
+ http_port_min = var.common_http_port_min
+ http_port_max = var.common_http_port_max
+ boot_wait = var.vm_boot_wait
+ boot_command = var.vm_boot_command
+
+ // Communicator Settings and Credentials
+ communicator = "winrm"
+ winrm_username = var.build_username
+ winrm_password = var.build_password
+ winrm_port = var.communicator_port
+ winrm_timeout = var.communicator_timeout
+
+ template_name = local.vm_name_pro
+ template_description = local.build_description
+
+}
+
+# Build Definition to create the VM Template
+source "proxmox-iso" "windows-desktop-ent" {
+
+ // Proxmox Connection Settings and Credentials
+ proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
+ username = var.proxmox_api_token_id
+ token = var.proxmox_api_token_secret
+ insecure_skip_tls_verify = var.proxmox_insecure_connection
+
+ // Proxmox Settings
+ node = var.proxmox_node
+
+ // Virtual Machine Settings
+ machine = var.vm_machine_type
+ vm_name = local.vm_name_ent
+ bios = var.vm_bios
+ sockets = var.vm_cpu_sockets
+ cores = var.vm_cpu_count
+ cpu_type = var.vm_cpu_type
+ memory = var.vm_mem_size
+ os = var.vm_os_type
+ qemu_agent = true
+ scsi_controller = var.vm_disk_controller_type
+
+ disks {
+ disk_size = var.vm_disk_size
+ type = var.vm_disk_type
+ storage_pool = var.vm_storage_pool
+ format = var.vm_disk_format
+ }
+
+ network_adapters {
+ bridge = var.vm_bridge_interface
+ model = var.vm_network_card_model
+ vlan_tag = var.vm_vlan_tag
+ }
+
+ tpm_config {
+ tpm_storage_pool = var.vm_tpm_storage_pool
+ tpm_version = var.vm_tpm_version
+ }
+
+ dynamic "efi_config" {
+ for_each = var.vm_bios == "ovmf" ? [1] : []
+ content {
+ efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
+ efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
+ pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
+ }
+ }
+
+ # Windows Server ISO File
+ boot_iso {
+
+ iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
+ unmount = true
+ iso_checksum = var.iso_checksum
+ type = "ide"
+ index = 0
+ }
+
+ // Removable Media Settings
+ additional_iso_files {
+ iso_file = "${var.common_iso_storage}:iso/virtio-win.iso"
+ iso_storage_pool = var.common_iso_storage
+ cd_label = "VirtIO"
+ unmount = true
+ }
+
+ additional_iso_files {
+ cd_files = [
+ "${path.cwd}/scripts/${var.vm_os_family}/"
+ ]
+ cd_content = {
+ "autounattend.xml" = templatefile("${abspath(path.root)}/data/autounattend.pkrtpl.hcl", {
+ build_username = var.build_username
+ build_password = var.build_password
+ vm_inst_os_eval = var.vm_inst_os_eval // Does not support evaluation.
+ vm_inst_os_language = var.vm_inst_os_language
+ vm_inst_os_keyboard = var.vm_inst_os_keyboard
+ vm_inst_os_image = var.vm_inst_os_image_ent
+ vm_inst_os_key = var.vm_inst_os_key_ent // Does not support evaluation.
+ vm_guest_os_language = var.vm_os_language
+ vm_guest_os_keyboard = var.vm_os_keyboard
+ vm_guest_os_timezone = var.vm_os_timezone
+ })
+ }
+ cd_label = "Unattend"
+ iso_storage_pool = var.common_iso_storage
+ unmount = true
+ }
+
+ // Boot and Provisioning Settings
+ http_port_min = var.common_http_port_min
+ http_port_max = var.common_http_port_max
+ boot_wait = var.vm_boot_wait
+ boot_command = var.vm_boot_command
+
+ // Communicator Settings and Credentials
+ communicator = "winrm"
+ winrm_username = var.build_username
+ winrm_password = var.build_password
+ winrm_port = var.communicator_port
+ winrm_timeout = var.communicator_timeout
+
+ template_name = local.vm_name_pro
+ template_description = local.build_description
+
+}
+// BLOCK: build
+// Defines the builders to run, provisioners, and post-processors.
+
+build {
+ sources = [
+ "source.proxmox-iso.windows-desktop-ent"
+ ]
+
+ provisioner "ansible" {
+ user = "${var.build_username}"
+ galaxy_file = "${path.cwd}/ansible/windows-requirements.yml"
+ galaxy_force_with_deps = true
+ use_proxy = false
+ playbook_file = "${path.cwd}/ansible/windows-playbook.yml"
+ roles_path = "${path.cwd}/ansible/roles"
+ ansible_env_vars = [
+ "ANSIBLE_CONFIG=${path.cwd}/ansible/ansible.cfg"
+ ]
+ extra_arguments = [
+ "--extra-vars", "use_proxy=false",
+ "--extra-vars", "ansible_connection=winrm",
+ "--extra-vars", "ansible_user='${var.build_username}'",
+ "--extra-vars", "ansible_password='${var.build_password}'",
+ "--extra-vars", "ansible_port='${var.communicator_port}'",
+ "--extra-vars", "build_username='${var.build_username}'",
+ ]
+ }
+
+ post-processor "manifest" {
+ output = local.manifest_output
+ strip_path = true
+ strip_time = true
+ custom_data = {
+ ansible_username = "${var.ansible_username}"
+ build_username = "${var.build_username}"
+ build_date = "${local.build_date}"
+ build_version = "${local.build_version}"
+ common_data_source = "${var.common_data_source}"
+ vm_cpu_sockets = "${var.vm_cpu_sockets}"
+ vm_cpu_count = "${var.vm_cpu_count}"
+ vm_disk_size = "${var.vm_disk_size}"
+ vm_bios = "${var.vm_bios}"
+ vm_os_type = "${var.vm_os_type}"
+ vm_mem_size = "${var.vm_mem_size}"
+ vm_network_card_model = "${var.vm_network_card_model}"
+ }
+ }
+}
diff --git a/builds/windows/desktop/11/windows.pkrvars.hcl.example b/builds/windows/desktop/11/windows.pkrvars.hcl.example
new file mode 100644
index 0000000..7d0c9ed
--- /dev/null
+++ b/builds/windows/desktop/11/windows.pkrvars.hcl.example
@@ -0,0 +1,20 @@
+/*
+ DESCRIPTION:
+ Microsoft Windows 11 build variables.
+ Packer Plugin for Proxmox: 'proxmox-iso' builder.
+*/
+
+// Installation Operating System Metadata
+vm_inst_os_key_pro = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"
+vm_inst_os_key_ent = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"
+
+// Virtual Machine Guest Operating System Setting
+vm_guest_os_type = "windows9_64Guest"
+
+// Virtual Machine Hardware Settings
+vm_firmware = "efi-secure"
+
+// Removable Media Settings
+iso_datastore_path = "iso/windows/windows-desktop/11/amd64"
+iso_content_library_item = "22631.2428.231001-0608.23H2_NI_RELEASE_SVC_REFRESH_CLIENTENTERPRISEEVAL_OEMRET_x64FRE_en-us"
+iso_file = "22631.2428.231001-0608.23H2_NI_RELEASE_SVC_REFRESH_CLIENTENTERPRISEEVAL_OEMRET_x64FRE_en-us.iso"
diff --git a/scripts/windows/windows-init.ps1 b/scripts/windows/windows-init.ps1
new file mode 100644
index 0000000..e28786b
--- /dev/null
+++ b/scripts/windows/windows-init.ps1
@@ -0,0 +1,30 @@
+<#
+ .DESCRIPTION
+ Enables Windows Remote Management on Windows builds.
+#>
+
+$ErrorActionPreference = 'Stop'
+
+# Set network connections provile to Private mode.
+Write-Output 'Setting the network connection profiles to Private...'
+$connectionProfile = Get-NetConnectionProfile
+While ($connectionProfile.Name -eq 'Identifying...') {
+ Start-Sleep -Seconds 10
+ $connectionProfile = Get-NetConnectionProfile
+}
+Set-NetConnectionProfile -Name $connectionProfile.Name -NetworkCategory Private
+
+# Set the Windows Remote Management configuration.
+Write-Output 'Setting the Windows Remote Management configuration...'
+winrm quickconfig -quiet
+winrm set winrm/config/service '@{AllowUnencrypted="true"}'
+winrm set winrm/config/service/auth '@{Basic="true"}'
+
+# Allow Windows Remote Management in the Windows Firewall.
+Write-Output 'Allowing Windows Remote Management in the Windows Firewall...'
+netsh advfirewall firewall set rule group="Windows Remote Administration" new enable=yes
+netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=allow
+
+# Reset the autologon count.
+# Reference: https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-autologon-logoncount#logoncount-known-issue
+Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name AutoLogonCount -Value 0
diff --git a/scripts/windows/windows-virtio.ps1 b/scripts/windows/windows-virtio.ps1
new file mode 100644
index 0000000..0b9a105
--- /dev/null
+++ b/scripts/windows/windows-virtio.ps1
@@ -0,0 +1,99 @@
+# Install Virtio Drivers
+
+function Enable-Virtio {
+Write-Host "Installing Virtio Drivers"
+# Search and Install virtio-win-gt-x64.msi Script
+
+# Get all file system drives
+$drives = Get-PSDrive -PSProvider 'FileSystem'
+
+# Loop through each drive to find and run the MSI installer
+foreach ($drive in $drives) {
+ $scriptFile = Join-Path $drive.Root 'virtio-win-gt-x64.msi'
+
+ # Check if the MSI file exists on the current drive
+ if (Test-Path $scriptFile) {
+ # Run the MSI installer with the specified arguments
+ Start-Process msiexec -Wait -ArgumentList '/i', $scriptFile, '/log', 'C:\Windows\Temp\qemu-drivers.log', '/qn', '/passive', '/norestart', 'ADDLOCAL=ALL' -ErrorAction SilentlyContinue
+ }
+}
+# Search and Install virtio-win-gt-x64.msi Script
+Write-Host "Installing QEMU Guest Agent"
+# Get all file system drives
+$drives = Get-PSDrive -PSProvider 'FileSystem'
+
+# Loop through each drive to find and run the MSI installer
+foreach ($drive in $drives) {
+ $scriptFile = Join-Path $drive.Root '/guest-agent/qemu-ga-x86_64.msi'
+
+ # Check if the MSI file exists on the current drive
+ if (Test-Path $scriptFile) {
+ # Run the MSI installer with the specified arguments
+ Start-Process msiexec -Wait -ArgumentList '/i', $scriptFile, '/log', 'C:\Windows\Temp\qemu-guest-agent.log', '/qn', '/passive', '/norestart', 'ADDLOCAL=ALL' -ErrorAction SilentlyContinue
+ }
+ }
+}
+
+# Write-Host "Installing SPICE"
+# # Search and Install virtio-win-guest-tools.exe
+
+# # Get all file system drives
+# $drives = Get-PSDrive -PSProvider 'FileSystem'
+
+# # Loop through each drive to find and run the MSI installer
+# foreach ($drive in $drives) {
+# $scriptFile = Join-Path $drive.Root 'virtio-win-guest-tools.exe'
+
+# # Check if the MSI file exists on the current drive
+# if (Test-Path $scriptFile) {
+# # Run the MSI installer with the specified arguments
+# Start-Process msiexec -Wait -ArgumentList '/i', $scriptFile, '/log', 'C:\Windows\Temp\qemu-drivers.log', '/qn', '/passive', '/norestart', 'ADDLOCAL=ALL' -ErrorAction SilentlyContinue
+# }
+# }
+If (Get-service -Name QEMU-GA -ErrorAction SilentlyContinue) {
+ Write-Host "Starting QEMU Guest Agent"
+ Start-Service -Name QEMU-GA -ErrorAction SilentlyContinue
+}
+
+If (Get-service -Name spice-agent -ErrorAction SilentlyContinue) {
+ Write-Host "Starting SPICE"
+ Start-Service -Name spice-agent -ErrorAction SilentlyContinue
+}
+
+Function Enable-WinRM {
+Write-Host "Enable WinRM"
+netsh advfirewall firewall set rule group="remote administration" new enable=yes
+netsh advfirewall firewall add rule name="WinRM open Port 5985" dir=in action=allow protocol=TCP localport=5985
+
+winrm quickconfig -q
+winrm quickconfig -transport:http
+winrm set winrm/config '@{MaxTimeoutms="7200000"}'
+winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="0"}'
+winrm set winrm/config/winrs '@{MaxProcessesPerShell="0"}'
+winrm set winrm/config/winrs '@{MaxShellsPerUser="0"}'
+winrm set winrm/config/service '@{AllowUnencrypted="true"}'
+winrm set winrm/config/service/auth '@{Basic="true"}'
+winrm set winrm/config/client/auth '@{Basic="true"}'
+
+net stop winrm
+sc.exe config winrm start= auto
+net start winrm
+
+}
+
+# http://support.microsoft.com/kb/154501
+Write-Host "Disabling automatic machine account password changes"
+Get-WmiObject -Class Win32_UserAccount -Filter "name = 'Administrator'" | Set-WmiInstance -Arguments @{PasswordExpires = 0 }
+
+$path = "HKLM:\System\CurrentControlSet\Services\Netlogon\Parameters"
+$key = try {
+ Get-Item -Path $path -ErrorAction Stop
+}
+catch {
+ New-Item -Path $path -Force
+}
+
+Set-ItemProperty -Path $key.PSPath -Name DisablePasswordChange -Value 1
+
+Enable-Virtio
+Enable-WinRM