From 9f1ff435ae8897222785ca57616fc6278f2191e9 Mon Sep 17 00:00:00 2001 From: AJ Schroeder <6432150+ajschroeder@users.noreply.github.com> Date: Thu, 20 Feb 2025 23:29:38 -0600 Subject: [PATCH] feat: add windows 11 build --- ansible/roles/base/tasks/main.yml | 4 +- ansible/roles/base/tasks/windows.yml | 51 +++ ansible/roles/configure/tasks/main.yml | 4 +- ansible/roles/configure/tasks/windows.yml | 133 ++++++ ansible/windows-playbook.yml | 8 + ansible/windows-requirements.yml | 8 + builds/proxy.pkrvars.hcl.example | 11 + .../desktop/11/data/autounattend.pkrtpl.hcl | 220 ++++++++++ builds/windows/desktop/11/variables.pkr.hcl | 413 ++++++++++++++++++ .../desktop/11/windows.auto.pkrvars.hcl | 43 ++ builds/windows/desktop/11/windows.pkr.hcl | 317 ++++++++++++++ .../desktop/11/windows.pkrvars.hcl.example | 20 + scripts/windows/windows-init.ps1 | 30 ++ scripts/windows/windows-virtio.ps1 | 99 +++++ 14 files changed, 1359 insertions(+), 2 deletions(-) create mode 100644 ansible/roles/base/tasks/windows.yml create mode 100644 ansible/roles/configure/tasks/windows.yml create mode 100644 ansible/windows-playbook.yml create mode 100644 ansible/windows-requirements.yml create mode 100644 builds/proxy.pkrvars.hcl.example create mode 100644 builds/windows/desktop/11/data/autounattend.pkrtpl.hcl create mode 100644 builds/windows/desktop/11/variables.pkr.hcl create mode 100644 builds/windows/desktop/11/windows.auto.pkrvars.hcl create mode 100644 builds/windows/desktop/11/windows.pkr.hcl create mode 100644 builds/windows/desktop/11/windows.pkrvars.hcl.example create mode 100644 scripts/windows/windows-init.ps1 create mode 100644 scripts/windows/windows-virtio.ps1 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</PlainText> + </Password> + <Enabled>true</Enabled> + <Username>${build_username}</Username> + </AutoLogon> + <OOBE> + <HideEULAPage>true</HideEULAPage> + <HideLocalAccountScreen>true</HideLocalAccountScreen> + <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> + <HideOnlineAccountScreens>true</HideOnlineAccountScreens> + <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> + <NetworkLocation>Work</NetworkLocation> + <ProtectYourPC>2</ProtectYourPC> + </OOBE> + <UserAccounts> + <AdministratorPassword> + <Value>${build_password}</Value> + <PlainText>true</PlainText> + </AdministratorPassword> + <LocalAccounts> + <LocalAccount wcm:action="add"> + <Password> + <Value>${build_password}</Value> + <PlainText>true</PlainText> + </Password> + <Group>administrators</Group> + <DisplayName>${build_username}</DisplayName> + <Name>${build_username}</Name> + <Description>Build Account</Description> + </LocalAccount> + </LocalAccounts> + </UserAccounts> + <FirstLogonCommands> + <SynchronousCommand wcm:action="add"> + <CommandLine>%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine> + <Description>Set Execution Policy 64-Bit</Description> + <Order>1</Order> + <RequiresUserInput>true</RequiresUserInput> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <CommandLine>%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine> + <Description>Set Execution Policy 32-Bit</Description> + <Order>2</Order> + <RequiresUserInput>true</RequiresUserInput> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <CommandLine>%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -File E:\windows-virtio.ps1</CommandLine> + <Order>3</Order> + <Description>Install VMware Tools</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <CommandLine>%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -File E:\windows-init.ps1</CommandLine> + <Order>4</Order> + <Description>Initial Configuration</Description> + </SynchronousCommand> + </FirstLogonCommands> + </component> + </settings> +</unattend> 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-<version>-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 = ["<spacebar><spacebar>"] +} + +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