From 4e3ef2b8e64ccc52156222158b6ee029e6565266 Mon Sep 17 00:00:00 2001 From: Ryan Ververs-Bijkerk Date: Mon, 29 May 2023 10:04:10 +0200 Subject: [PATCH 1/5] Update in Citrix playbooks --- ansible/citrix-license-server.yml | 2 +- ansible/citrix-storefront.yml | 2 +- ansible/roles/citrix-license-server/tasks/main.yml | 3 --- ansible/roles/citrix-storefront/tasks/install.yml | 3 --- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ansible/citrix-license-server.yml b/ansible/citrix-license-server.yml index 6334c31..e9573d4 100644 --- a/ansible/citrix-license-server.yml +++ b/ansible/citrix-license-server.yml @@ -16,7 +16,7 @@ vars: ou_path: "OU=Infra,OU=Machines,OU=GO" -- name: Citrix License Server +- name: Install and configure Citrix License Server hosts: citrix_lic roles: - citrix-license-server diff --git a/ansible/citrix-storefront.yml b/ansible/citrix-storefront.yml index 88a61e6..d96d135 100644 --- a/ansible/citrix-storefront.yml +++ b/ansible/citrix-storefront.yml @@ -16,7 +16,7 @@ vars: ou_path: "OU=Infra,OU=Machines,OU=GO" -- name: Citrix Storefront +- name: Install and configure Citrix Storefront hosts: citrix_sf roles: - citrix-storefront diff --git a/ansible/roles/citrix-license-server/tasks/main.yml b/ansible/roles/citrix-license-server/tasks/main.yml index 4100f94..a1b024d 100644 --- a/ansible/roles/citrix-license-server/tasks/main.yml +++ b/ansible/roles/citrix-license-server/tasks/main.yml @@ -8,9 +8,6 @@ - name: Block for Citrix installation block: - - name: Install NuGet - win_shell: Install-PackageProvider -Name Nuget -Force - - name: Check for PendingReboot module win_psmodule: name: PendingReboot diff --git a/ansible/roles/citrix-storefront/tasks/install.yml b/ansible/roles/citrix-storefront/tasks/install.yml index 1275127..1ebd0de 100644 --- a/ansible/roles/citrix-storefront/tasks/install.yml +++ b/ansible/roles/citrix-storefront/tasks/install.yml @@ -8,9 +8,6 @@ - name: Block for Citrix installation block: - - name: Install NuGet - win_shell: Install-PackageProvider -Name Nuget -Force - - name: Check for PendingReboot module win_psmodule: name: PendingReboot From db801ac1e3e8ed7c62f8ef5e7be6aa1ef393e4c1 Mon Sep 17 00:00:00 2001 From: Ryan Ververs-Bijkerk Date: Mon, 29 May 2023 10:04:24 +0200 Subject: [PATCH 2/5] Minor tweak in readme --- init/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/init/README.md b/init/README.md index 7f583ce..6a1814c 100644 --- a/init/README.md +++ b/init/README.md @@ -1,4 +1,3 @@ -__TOC__ The goal of the initialization script is to begin the deployment of the GO-EUC infrastructure. It will deploy the initial requirements depending on the platform and provision the project in your Azure DevOps environment. Once the project is provisioned, you will have the ability to start deploying the rest of the infrastructure. @@ -148,7 +147,7 @@ Start the init script as followed: As mentioned earlier, the init script will provision your environment and consists of the following steps: 1. Collecting the settings.json file and converting it to an object -2. Installing required modules: Posh-SSH and Indented.Net.IP +2 .Installing required modules: Posh-SSH and Indented.Net.IP 3. Clearing any existing trusted SSH hosts 4. Calculating the network range based on CIDR 5. Collecting and downloading Hashicorp Terraform, Packer & Vault binaries via Evergreen (stealthpuppy.com) From c20a051a1fc936af53de194e9b901498de30db57 Mon Sep 17 00:00:00 2001 From: Ryan Ververs-Bijkerk Date: Wed, 16 Aug 2023 08:24:16 +0200 Subject: [PATCH 3/5] Major sync based on local lab --- ansible/loadgen.yml | 36 +++-- .../tasks/install.yml | 3 + .../citrix-license-server/tasks/main.yml | 3 + ansible/roles/citrix-receiver/tasks/main.yml | 23 +++- .../roles/citrix-storefront/tasks/install.yml | 3 + ansible/roles/citrix-vda/tasks/main.yml | 54 +------- ansible/roles/domain-join/tasks/main.yml | 4 + ansible/roles/windows-image/files/GO-EUC.xml | 23 ++++ .../windows-image/tasks/adobe-reader-dc.yml | 23 ++++ .../windows-image/tasks/citrix-optimizer.yml | 23 ++++ .../roles/windows-image/tasks/citrix-vda.yml | 130 +++++------------- .../windows-image/tasks/loadgen-addin.yml | 100 ++++++++++++++ ansible/roles/windows-image/tasks/main.yml | 28 ++++ ansible/roles/windows-image/tasks/nvidia.yml | 26 ++++ .../roles/windows-image/tasks/office365.yml | 56 ++++++++ ansible/updates.yml | 43 ++++++ ansible/vars/citrix.yml | 7 +- ansible/vars/loadgen.yml | 2 +- ansible/vars/nvidia.yml | 5 + ansible/windows-image.yml | 19 ++- init/README.md | 2 +- init/azure/README.md | 20 +++ .../scripts/windows/windows-prepare.ps1 | 6 + .../windows/desktop/11/variables.pkr.hcl | 5 - .../windows/desktop/11/windows-client.pkr.hcl | 3 +- terraform/vmware/infra/outputs.tf | 10 +- terraform/vmware/infra/resource.tf | 57 +++++++- 27 files changed, 532 insertions(+), 182 deletions(-) create mode 100644 ansible/roles/windows-image/files/GO-EUC.xml create mode 100644 ansible/roles/windows-image/tasks/adobe-reader-dc.yml create mode 100644 ansible/roles/windows-image/tasks/citrix-optimizer.yml create mode 100644 ansible/roles/windows-image/tasks/loadgen-addin.yml create mode 100644 ansible/roles/windows-image/tasks/nvidia.yml create mode 100644 ansible/roles/windows-image/tasks/office365.yml create mode 100644 ansible/updates.yml create mode 100644 ansible/vars/nvidia.yml create mode 100644 init/azure/README.md diff --git a/ansible/loadgen.yml b/ansible/loadgen.yml index ddff9bb..829fca6 100644 --- a/ansible/loadgen.yml +++ b/ansible/loadgen.yml @@ -9,18 +9,28 @@ # - name: Start the Azure Key Vault actions # include_tasks: azure-keyvault.yml -- name: LoadGen Bots - hosts: lg_bots +- hosts: localhost + connection: local + gather_facts: yes + tasks: + - name: Install requirements + include_tasks: vault.yml + +- name: Domain join the LoadGen bots + hosts: bots roles: - - domain-join - - citrix-receiver - - loadgen-agent + - domain-join + vars_files: + - ansible.yml + - local.yml vars: - dns_domain_name: 'GO.EUC' - domain_name: GO - domain_controller: "{{ groups['dc'][0] }}" - domain_admin_user: "GO\\{{ ansible_user }}" - ansible_connection: winrm - ansible_winrm_transport: ntlm - ansible_winrm_server_cert_validation: ignore - ansible_port: 5985 + ou_path: "OU=Bots,OU=Machines,OU=GO" + +- name: Install and configure the LoadGen bots + hosts: bots + roles: + - citrix-receiver + vars_files: + - ansible.yml + - domain.yml + - loadgen.yml diff --git a/ansible/roles/citrix-delivery-controller/tasks/install.yml b/ansible/roles/citrix-delivery-controller/tasks/install.yml index bd44bc1..58255e3 100644 --- a/ansible/roles/citrix-delivery-controller/tasks/install.yml +++ b/ansible/roles/citrix-delivery-controller/tasks/install.yml @@ -8,6 +8,9 @@ - name: Block for Citrix installation block: + - name: Install NuGet + win_shell: Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + - name: Check for PendingReboot module win_psmodule: name: PendingReboot diff --git a/ansible/roles/citrix-license-server/tasks/main.yml b/ansible/roles/citrix-license-server/tasks/main.yml index a1b024d..3bfeecc 100644 --- a/ansible/roles/citrix-license-server/tasks/main.yml +++ b/ansible/roles/citrix-license-server/tasks/main.yml @@ -8,6 +8,9 @@ - name: Block for Citrix installation block: + - name: Install NuGet + win_shell: Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + - name: Check for PendingReboot module win_psmodule: name: PendingReboot diff --git a/ansible/roles/citrix-receiver/tasks/main.yml b/ansible/roles/citrix-receiver/tasks/main.yml index 92c660b..e514ffe 100644 --- a/ansible/roles/citrix-receiver/tasks/main.yml +++ b/ansible/roles/citrix-receiver/tasks/main.yml @@ -1,8 +1,23 @@ --- -- name: Install Citrix Receiver +- name: Update fact to CitrixWorkspaceApp + set_fact: + app_name: CitrixWorkspaceApp + +- name: "Collect Evergreen info for {{ app_name }}" + win_uri: + url: "https://evergreen-api.stealthpuppy.com/app/{{ app_name }}" + method: GET + content_type: application/json + return_content: true + register: app + +- name: "Set Evergreen object for {{ app_name }}" + set_fact: + app_details: "{{ app.json | json_query('[?Stream == `Current`]') | first }}" + +- name: "Install {{ app_details.Title }} {{ app_details.Version }}" win_package: - path: "https://downloadplugins.citrix.com/ReceiverUpdates/Prod/Receiver/Win/CitrixWorkspaceApp22.7.0.24.exe" + path: "{{ app_details.URI }}" arguments: /silent /noreboot /AutoUpdateCheck=disabled - state: present expected_return_code: [0, 3, 3010] - creates_path: "C:\\Program Files (x86)\\Citrix\\Citrix WorkSpace 2207" + state: present diff --git a/ansible/roles/citrix-storefront/tasks/install.yml b/ansible/roles/citrix-storefront/tasks/install.yml index 1ebd0de..b8c76ca 100644 --- a/ansible/roles/citrix-storefront/tasks/install.yml +++ b/ansible/roles/citrix-storefront/tasks/install.yml @@ -8,6 +8,9 @@ - name: Block for Citrix installation block: + - name: Install NuGet + win_shell: Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + - name: Check for PendingReboot module win_psmodule: name: PendingReboot diff --git a/ansible/roles/citrix-vda/tasks/main.yml b/ansible/roles/citrix-vda/tasks/main.yml index aadf51e..c9f049a 100644 --- a/ansible/roles/citrix-vda/tasks/main.yml +++ b/ansible/roles/citrix-vda/tasks/main.yml @@ -1,18 +1,4 @@ --- -- name: Built the environment dictonary and variables - set_fact: - branch: "{{ lookup('env', 'environment') | lower }}" - environments: - default: "pois" - cards: "card" - flowers: "flow" - -- name: Built the environment dictonary and variables - set_fact: - citrix_username: "{{ lookup('env', 'citrix_username') }}" - citrix_password: "{{ lookup('env', 'citrix_password') }}" - environment_short: "{{ environments[branch] }}" - - name: Install Microsoft Visual C++ Redistributable Latest - X86" win_package: path: https://aka.ms/vs/17/release/vc_redist.x86.exe @@ -32,33 +18,10 @@ win_reboot: reboot_timeout: 3600 -- name: Create directory structure - win_file: - path: C:\Download\Citrix - state: directory - -- name: Copy a single file - ansible.windows.win_copy: - src: files/Get-CTXBinary.ps1 - dest: C:\Download\Citrix\Get-CTXBinary.ps1 - -- name: Debug Citrix download - ansible.builtin.debug: - msg: "{{ citrix_username }}" - -- name: Download Citrix VDA - win_shell: C:\Download\Citrix\Get-CTXBinary.ps1 -DownloadPath C:\Download\Citrix\ -MyCitrixUsername "{{ citrix_username }}" -MyCitrixPassword "{{ citrix_password }}" -VDAVersion latest -VDAType server - register: citrix_download - -- name: Debug Citrix download - ansible.builtin.debug: - msg: "{{ citrix_download }}" - - name: Install Citrix VDA win_package: - chdir: C:\Download\Citrix - path: "{{ citrix_download.stdout | trim }}" - arguments: /components VDA /controllers "{{ environment_short }}-cc-1.go.euc, {{ environment_short }}-cc-2.go.euc" /disableexperiencemetrics /enable_hdx_ports /enable_hdx_udp_ports /enable_real_time_transport /enable_remote_assistance /enable_ss_ports /exclude `"Citrix Telemetry Service`",`"Citrix Personalization for App-V - VDA`",`"Citrix Files for Windows`",`"Citrix Files for Outlook`",`"User personalization layer`",`"Citrix WEM Agent`",`"Citrix VDA Upgrade Agent`" /includeadditional `"Citrix MCS IODriver`" /masterimage /noreboot /quiet + path: "{{citrix.path}}/{{citrix.version}}/VDAWorkstationSetup_{{citrix.version}}.exe" + arguments: /components VDA /disableexperiencemetrics /enable_hdx_ports /enable_hdx_udp_ports /enable_real_time_transport /masterimage /noreboot /quiet state: present expected_return_code: [0, 3, 3010] register: vda_install @@ -66,16 +29,3 @@ - name: Reboot after VDA win_reboot: when: vda_install.changed - -- name: Resume VDA Install - win_package: - path: "{{ citrix_download.stdout | trim }}" - state: present - expected_return_code: [0, 3, 3010] - creates_service: BrokerAgent - when: vda_install.changed - register: vda_resume - -- name: Reboot after vda install - win_reboot: - when: vda_resume.changed diff --git a/ansible/roles/domain-join/tasks/main.yml b/ansible/roles/domain-join/tasks/main.yml index c9b0249..5d354c5 100644 --- a/ansible/roles/domain-join/tasks/main.yml +++ b/ansible/roles/domain-join/tasks/main.yml @@ -2,6 +2,10 @@ - name: Domain join machine block: + - name: Set timezone to 'W. Europe Standard Time' (GMT+01:00) + win_timezone: + timezone: W. Europe Standard Time + - name: Set fact for Domain Path set_fact: domain_path: "DC={{ dns_domain_name.split('.') | join(',DC=') }}" diff --git a/ansible/roles/windows-image/files/GO-EUC.xml b/ansible/roles/windows-image/files/GO-EUC.xml new file mode 100644 index 0000000..480f411 --- /dev/null +++ b/ansible/roles/windows-image/files/GO-EUC.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ansible/roles/windows-image/tasks/adobe-reader-dc.yml b/ansible/roles/windows-image/tasks/adobe-reader-dc.yml new file mode 100644 index 0000000..f650444 --- /dev/null +++ b/ansible/roles/windows-image/tasks/adobe-reader-dc.yml @@ -0,0 +1,23 @@ +--- +- name: Update fact to AdobeAcrobatReaderDC + set_fact: + app_name: AdobeAcrobatReaderDC + +- name: "Collect Evergreen info for {{ app_name }}" + win_uri: + url: "https://evergreen-api.stealthpuppy.com/app/{{ app_name }}" + method: GET + content_type: application/json + return_content: true + register: app + +- name: "Set Evergreen object for {{ app_name }}" + set_fact: + app_details: "{{ app.json | json_query('[?Architecture == `x64` && Language == `MUI`]') | first }}" + +- name: "Install {{ app_details.Title }} {{ app_details.Version }}" + win_package: + path: "{{ app_details.URI }}" + arguments: /sAll /rs /msi EULA_ACCEPT=YES + expected_return_code: [0, 3, 3010] + state: present diff --git a/ansible/roles/windows-image/tasks/citrix-optimizer.yml b/ansible/roles/windows-image/tasks/citrix-optimizer.yml new file mode 100644 index 0000000..5251c80 --- /dev/null +++ b/ansible/roles/windows-image/tasks/citrix-optimizer.yml @@ -0,0 +1,23 @@ +--- +- name: Create Temp folder + win_file: + path: C:\Temp + state: directory + +- name: Download Citrix Optimizer + win_get_url: + url: "{{citrix.optimizer.path}}/{{citrix.optimizer.version}}/CitrixOptimizerTool.zip" + dest: C:\Temp\CitrixOptimizerTool.zip + +- name: Extract zip file + win_unzip: + src: C:\Temp\CitrixOptimizerTool.zip + dest: C:\Temp\ + +- name: Apply optimizations + win_shell: C:\Temp\CtxOptimizerEngine.ps1 -Template AutoSelect -Mode Execute + +- name: Remove Temp directory structure + win_file: + path: C:\Temp + state: absent \ No newline at end of file diff --git a/ansible/roles/windows-image/tasks/citrix-vda.yml b/ansible/roles/windows-image/tasks/citrix-vda.yml index 29f03da..ee71a18 100644 --- a/ansible/roles/windows-image/tasks/citrix-vda.yml +++ b/ansible/roles/windows-image/tasks/citrix-vda.yml @@ -1,95 +1,37 @@ --- -- name: Obtain information from registry for site check - win_reg_stat: - path: HKLM:\Software\GO-EUC\Citrix - name: version - register: citrix_version - -- name: Block for Citrix installation - block: - - - name: Set fact for Workstation - set_fact: - citrix_type: Workstation - when: ansible_facts.os_installation_type == 'Client' - - - name: Set fact for Server - set_fact: - citrix_type: Server - when: ansible_facts.os_installation_type == 'Server' - - - name: Check pending reboot - import_tasks: pending-reboot.yml - - - name: Create Citrix temp directory - win_file: - path: C:\Temp\Citrix - state: directory - - - name: Check if Citrix VDA is copied - win_stat: - path: "C:\\Temp\\Citrix\\VDA{{citrix_type}}Setup_{{citrix.version}}.exe" - register: citrix_source - - - name: Copy file from UNC path - win_copy: - src: "{{citrix.path}}\\v{{citrix.version}}\\VDA{{citrix_type}}Setup_{{citrix.version}}.exe" - dest: "C:\\Temp\\Citrix\\VDA{{citrix_type}}Setup_{{citrix.version}}.exe" - remote_src: true - vars: - ansible_become: true - ansible_become_user: "{{ domain_name }}\\Administrator" - ansible_become_password: "{{ ansible_password }}" - ansible_become_method: runas - when: citrix_source.stat.exists == false - - - name: Install Microsoft Visual C++ Redistributable Latest - X86" - win_package: - path: https://aka.ms/vs/17/release/vc_redist.x86.exe - arguments: /q /norestart - - - name: Install Microsoft Visual C++ Redistributable Latest - X64" - win_package: - path: https://aka.ms/vs/17/release/vc_redist.x64.exe - arguments: /q /norestart - - - name: Install Microsoft .NET Framework 4.8 - Offline installer - win_package: - path: https://go.microsoft.com/fwlink/?linkid=2088631 - arguments: /q /norestart - - - name: Check pending reboot - import_tasks: pending-reboot.yml - - - name: Install Citrix VDA - win_package: - path: "C:\\Temp\\Citrix\\VDA{{citrix_type}}Setup_{{citrix.version}}.exe" - arguments: /components VDA /controllers "{{ groups['ctx_ddc'] | join(', ') }}" /disableexperiencemetrics /enable_hdx_ports /enable_hdx_udp_ports /enable_real_time_transport /enable_remote_assistance /enable_ss_ports /exclude `"Citrix Telemetry Service`",`"Citrix Personalization for App-V - VDA`",`"Citrix Files for Windows`",`"Citrix Files for Outlook`",`"User personalization layer`",`"Citrix WEM Agent`",`"Citrix VDA Upgrade Agent`" /includeadditional `"Citrix MCS IODriver`" /masterimage /noreboot /quiet - state: present - expected_return_code: [0, 3, 3010] - register: install - - - name: Reboot after VDA - win_reboot: - when: vda_install.reboot_required - - - name: Resume VDA Install - win_package: - path: "C:\\Temp\\Citrix\\VDA{{citrix_type}}Setup_{{citrix.version}}.exe" - state: present - expected_return_code: [0, 3, 3010] - when: vda_install.changed - register: install_resume - - - name: Reboot after vda install - win_reboot: - when: install_resume.reboot_required - - - name: Add registry for future installation check - win_regedit: - path: HKLM:\Software\GO-EUC\Citrix - name: version - data: "{{ citrix.version }}" - type: string - - when: (citrix_version.exists == false) or (citrix_version.value != citrix.version) +- name: Set fact for Workstation + set_fact: + citrix_type: Workstation + when: ansible_facts.os_installation_type == 'Client' + +- name: Set fact for Server + set_fact: + citrix_type: Server + when: ansible_facts.os_installation_type == 'Server' + +- name: Install Microsoft Visual C++ Redistributable Latest - X86" + win_package: + path: https://aka.ms/vs/17/release/vc_redist.x86.exe + arguments: /q /norestart + +- name: Install Microsoft Visual C++ Redistributable Latest - X64" + win_package: + path: https://aka.ms/vs/17/release/vc_redist.x64.exe + arguments: /q /norestart + +- name: Install Microsoft .NET Framework 4.8 - Offline installer + win_package: + path: https://go.microsoft.com/fwlink/?linkid=2088631 + arguments: /q /norestart + +- name: Install Citrix VDA + win_package: + path: "{{citrix.path}}/{{citrix.version}}/VDAWorkstationSetup_{{citrix.version}}.exe" + arguments: /components VDA /disableexperiencemetrics /enable_hdx_ports /enable_hdx_udp_ports /enable_real_time_transport /masterimage /noreboot /quiet + state: present + expected_return_code: [0, 3, 3010] + register: install + +- name: Reboot after VDA + win_reboot: + when: install.reboot_required diff --git a/ansible/roles/windows-image/tasks/loadgen-addin.yml b/ansible/roles/windows-image/tasks/loadgen-addin.yml new file mode 100644 index 0000000..802b643 --- /dev/null +++ b/ansible/roles/windows-image/tasks/loadgen-addin.yml @@ -0,0 +1,100 @@ +--- +- name: Set variables + set_fact: + delivery: "{{ lookup('ansible.builtin.env', 'delivery') }}" + +- name: Get WinRM memory configuration + win_shell: (Get-Item -Path WSMan:\localhost\Shell\MaxMemoryPerShellMB).Value + register: winrm_mem + +- name: Cleanup fact for WinRM memory + ansible.builtin.set_fact: + winrm_memory: winrm_mem.stdout | trim + +- name: Set the WinRM memory to 4GB # This is required to download LoadGen data + win_shell: Set-Item -Path WSMan:\localhost\Shell\MaxMemoryPerShellMB -Value 4096 + when: winrm_memory != "4096" + +- name: Force reboot to apply WinRM config + win_reboot: + when: winrm_memory != "4096" + +- name: Create directory structure + win_file: + path: C:\Download\LoadGen + state: directory + +- name: Check if LoadGen is downloaded yet + win_stat: + path: C:\Download\LoadGen\LoadGenSuite.zip + register: download_file + +- name: Download LoadGen Suite + win_get_url: + url: "https://download.loadgen.cloud/loadgen/CurrentMSI/LoadGenSuite.zip" + dest: C:\Download\LoadGen\LoadGenSuite.zip + when: download_file.stat.exists == False + +- name: Check if LoadGen is exctracted yet + win_stat: + path: C:\Download\LoadGen\LoadGenSuite.exe + register: extracted_file + +- name: Extract LoadGen Suite zip + win_unzip: + src: C:\Download\LoadGen\LoadGenSuite.zip + dest: C:\Download\LoadGen\ + creates: C:\Download\LoadGen\LoadGenSuite.exe + when: extracted_file.stat.exists == False + +- name: Install LoadGen + win_package: + path: C:\Download\LoadGen\LoadGenSuite.exe + product_id: '{ED23CB99-3CCE-493E-8724-531632A2ACDD}' # LoadGen 5.0 + arguments: /S /v/qn + expected_return_code: [0] + state: present + +- name: Check if LoadGen Agent is installed + win_stat: + path: C:\Program Files\LoadGen\LoadGen Agent\LoadGen LoadBot Agent.exe + register: loadgen_agent + +- name: Create ProgramData directory structure for Agent + win_file: + path: C:\ProgramData\LoadGen\Download\Agent + state: directory + when: loadgen_agent.stat.exists == False + +- name: Download LoadGen Agent + win_get_url: + url: "https://download.loadgen.cloud/loadgen/{{ loadgen.version }}/LoadGenAgent.txt" + dest: C:\ProgramData\LoadGen\Download\Agent\AutoUpdate.dat + when: loadgen_agent.stat.exists == False + +- name: Run AutoUpdater for LoadGen Agent + win_command: '"C:\Program Files\LoadGen\AutoUpdater.exe" -i "C:\ProgramData\LoadGen\Download\Agent\AutoUpdate.dat"' + when: loadgen_agent.stat.exists == False + +- name: Register Add-In services for Citrix + win_shell: '& "C:\Program Files\LoadGen\LoadGen Agent\LoadGenUAICitrix\LoadGenUAI.ServerAddinLauncherSrvc.exe" -i' + when: delivery == 'citrix' + +- name: Register Add-In services + win_shell: '& "C:\Program Files\LoadGen\LoadGen Agent\LoadGenUAI\LoadGenUAI.ServerAddinLauncherSrvc.exe" -i' + when: delivery != 'citrix' + +- name: Uninstall LoadGen + win_package: + product_id: '{ED23CB99-3CCE-493E-8724-531632A2ACDD}' # LoadGen 5.0 + state: absent + +- name: Remove ProgramData download directory structure + win_file: + path: C:\ProgramData\LoadGen\Download + state: absent + +- name: Remove download directory structure + win_file: + path: C:\Download + state: absent diff --git a/ansible/roles/windows-image/tasks/main.yml b/ansible/roles/windows-image/tasks/main.yml index 6a4bbce..dd45687 100644 --- a/ansible/roles/windows-image/tasks/main.yml +++ b/ansible/roles/windows-image/tasks/main.yml @@ -1,8 +1,24 @@ --- +- name: Set variables + set_fact: + delivery: "{{ lookup('ansible.builtin.env', 'delivery') }}" + gpu_check: "{{ lookup('ansible.builtin.env', 'vgpu') }}" + - name: Deployment Information debug: msg: "Running deployment for {{delivery}} on {{ansible_facts.os_name}}" +- name: Add registry DelayedDesktopSwitchTimeout to value 0 + win_regedit: + path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System + name: DelayedDesktopSwitchTimeout + data: 0 + type: dword + +- name: Install NVIDIA driver + import_tasks: nvidia.yml + when: gpu_check == true + - name: Install Citrix VDA import_tasks: citrix-vda.yml when: delivery == 'citrix' @@ -11,9 +27,21 @@ import_tasks: vmware-horizon.yml when: delivery == 'vmware' +- name: Install LoadGen AddIn + import_tasks: loadgen-addin.yml + +- name: Install Office 365 + import_tasks: office365.yml + +- name: Install Adobe Reader DC + import_tasks: adobe-reader-dc.yml + - name: Apply Windows updates import_tasks: updates.yml +- name: Apply Citrix Optimizer + import_tasks: citrix-optimizer.yml + - name: Deployment Information debug: msg: "Complete deployment for {{delivery}} on {{ansible_facts.os_name}}" diff --git a/ansible/roles/windows-image/tasks/nvidia.yml b/ansible/roles/windows-image/tasks/nvidia.yml new file mode 100644 index 0000000..eb17e1b --- /dev/null +++ b/ansible/roles/windows-image/tasks/nvidia.yml @@ -0,0 +1,26 @@ +--- +- name: Create Temp Folder + win_file: + path: C:\Temp + state: directory + +- name: Download NVIDIA Driver + win_get_url: + url: "{{nvidia.path}}/NVIDIA.zip" + dest: C:\Temp\NVIDIA.zip + +- name: Unzip gz log + win_unzip: + src: C:\Temp\NVIDIA.zip + dest: C:\Temp\NVIDIA + +- name: Install NVIDIA + win_package: + path: C:\Temp\NVIDIA\setup.exe + expected_return_code: [0, 1, 3010] + arguments: -s -noreboot + +- name: Download license file + win_get_url: + url: "{{nvidia.path}}/{{nvidia.license}}" + dest: "C:\\Program Files\\NVIDIA Corporation\\vGPU Licensing\\ClientConfigToken\\{{ nvidia.license }}" diff --git a/ansible/roles/windows-image/tasks/office365.yml b/ansible/roles/windows-image/tasks/office365.yml new file mode 100644 index 0000000..4853be1 --- /dev/null +++ b/ansible/roles/windows-image/tasks/office365.yml @@ -0,0 +1,56 @@ +--- +- name: Microsoft Teams System installer + win_regedit: + path: HKLM:\Software\Microsoft\Teams + name: IsWVDEnvironment + data: 1 + type: dword + +- name: Install the Teams WebSocket Service for AVD + win_package: + path: https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RWQ1UW + arguments: /qn + when: lookup('env', 'delivery') == 'avd' + +- name: Extract "Office Deployment Tool" + win_package: + path: https://download.microsoft.com/download/2/7/A/27AF1BE6-DD20-4CB4-B154-EBAB8A7D4A7E/officedeploymenttool_16626-20148.exe + creates_path: C:\ODTSetup + arguments: /extract:C:\ODTSetup /quiet + +- name: Copy a single file + win_copy: + src: files/GO-EUC.xml + dest: C:\ODTSetup\GO-EUC.xml + +- name: Install "Microsoft 365 Apps for Enterprise - Semi-Anual enterprise channel" + win_package: + path: C:\ODTSetup\setup.exe + arguments: /configure C:\ODTSetup\GO-EUC.xml + +# Details from Pieter Wigleven here - https://twitter.com/PieterWigleven/status/1280554361739833345 +- name: Install 10 day testing license from Pieter Wigleven + win_package: + chdir: C:\Program Files\Microsoft Office\Office16 + path: C:\Windows\system32\cscript.exe + arguments: OSPP.VBS /inpkey:DRNV7-VGMM2-B3G9T-4BF84-VMFTK + +- name: M365 - Disable Activation UI + win_regedit: + path: HKLM:\Software\Microsoft\Office\16.0\Common\Licensing + name: DisableActivationUI + data: 1 + type: dword + +# The Accept EULA needs to be in the User GPO. Since this an user setting +- name: M365 - Accept EULA + win_regedit: + path: HKCU:\Software\Microsoft\Office\16.0\Registration + name: AcceptAllEulas + data: 1 + type: dword + +- name: Remove ODTSetup directory structure + win_file: + path: C:\ODTSetup + state: absent \ No newline at end of file diff --git a/ansible/updates.yml b/ansible/updates.yml new file mode 100644 index 0000000..333e62a --- /dev/null +++ b/ansible/updates.yml @@ -0,0 +1,43 @@ +--- +- hosts: localhost + connection: local + gather_facts: yes + tasks: + - name: Install requirements and collect secrets + include_tasks: vault.yml + +- name: Install Windows Updates and set timezone + hosts: all + tasks: + + - name: Set timezone to 'W. Europe Standard Time' (GMT+01:00) + win_timezone: + timezone: W. Europe Standard Time + + - name: "Reset Windows Update agent cache" + win_shell: | + Stop-Service -Name BITS,WUAUSERV,WaaSMedicSvc,CryptSvc -Force + Remove-Item -Path C:\Windows\SoftwareDistribution -Recurse -Force + Remove-Item -Path C:\Windows\System32\catroot2 -Recurse -Force + Start-Service -Name BITS,WUAUSERV,WaaSMedicSvc,CryptSvc + Usoclient RefreshSettings + Usoclient ScanInstallWait + register: reset_windows_update_results + become: yes + become_method: runas + become_user: SYSTEM + + - name: Install Windows Updates + win_updates: + category_names: '*' + reboot: no + state: installed + log_path: C:\Windows\Temp\ansible_updates.txt + + - name: Force reboot after the Windows Updates + win_reboot: + reboot_timeout: 3600 + + vars_files: + - ansible.yml + - domain.yml \ No newline at end of file diff --git a/ansible/vars/citrix.yml b/ansible/vars/citrix.yml index 8c06d35..44750bc 100644 --- a/ansible/vars/citrix.yml +++ b/ansible/vars/citrix.yml @@ -1,7 +1,7 @@ --- citrix: - version: '2212' - source: Citrix_Virtual_Apps_and_Desktops_7_2212.iso + version: '2305' + source: Citrix_Virtual_Apps_and_Desktops_7_2305.iso path: "http://10.2.0.6:8080/Citrix/CVAD" site: Default database_port: 1433 @@ -12,6 +12,9 @@ citrix: role: Full Administrator scope: All grooming: 365 + optimizer: + path: "http://10.2.0.6:8080/Citrix/Optimizer" + version: 3103 licensing: port: 27000 model: Concurrent diff --git a/ansible/vars/loadgen.yml b/ansible/vars/loadgen.yml index cbe31f4..07a1284 100644 --- a/ansible/vars/loadgen.yml +++ b/ansible/vars/loadgen.yml @@ -1,6 +1,6 @@ --- loadgen: - version: 8229 + version: 8608 profile: name: GO-Admin workgroup: false diff --git a/ansible/vars/nvidia.yml b/ansible/vars/nvidia.yml new file mode 100644 index 0000000..53c9265 --- /dev/null +++ b/ansible/vars/nvidia.yml @@ -0,0 +1,5 @@ +--- +nvidia: + path: http://10.2.0.6:8080/NVIDIA/GRID/ + version: 528.24 + license: license.tok \ No newline at end of file diff --git a/ansible/windows-image.yml b/ansible/windows-image.yml index 95f8d2e..44d4167 100644 --- a/ansible/windows-image.yml +++ b/ansible/windows-image.yml @@ -1,16 +1,23 @@ --- +- hosts: localhost + connection: local + gather_facts: yes + tasks: + - name: Install requirements + include_tasks: vault.yml + - name: Domain join - hosts: builds + hosts: "build[{{build_id}}]" roles: - domain-join vars_files: - ansible.yml - - domain.yml + - local.yml vars: - ansible_user: "{{ local_admin_user }}" + ou_path: "OU=Builds,OU=Machines,OU=GO" - name: Installation playbook for base image - hosts: builds + hosts: "build[{{build_id}}]" roles: - windows-image vars_files: @@ -18,5 +25,5 @@ - domain.yml - citrix.yml - vmware.yml - vars: - ansible_user: "{{ domain_admin_user }}" + - loadgen.yml + - nvidia.yml diff --git a/init/README.md b/init/README.md index 6a1814c..dd4d915 100644 --- a/init/README.md +++ b/init/README.md @@ -147,7 +147,7 @@ Start the init script as followed: As mentioned earlier, the init script will provision your environment and consists of the following steps: 1. Collecting the settings.json file and converting it to an object -2 .Installing required modules: Posh-SSH and Indented.Net.IP +2. Installing required modules: Posh-SSH and Indented.Net.IP 3. Clearing any existing trusted SSH hosts 4. Calculating the network range based on CIDR 5. Collecting and downloading Hashicorp Terraform, Packer & Vault binaries via Evergreen (stealthpuppy.com) diff --git a/init/azure/README.md b/init/azure/README.md new file mode 100644 index 0000000..b9867a2 --- /dev/null +++ b/init/azure/README.md @@ -0,0 +1,20 @@ +## Flow +As mentioned earlier, the init script will provision your environment and consists of the following steps: + +1. Collecting the settings.json file and converting it to an object +2. Collecting and downloading Hashicorp Terraform & Vault binaries via Evergreen (stealthpuppy.com) +3. AZ Login for creation of the SPN account +4. Switch to correct tennant and subscription based on the settings.json (or paramter) +5. Create SPN for deployment +6. Collect public IP dynamic or via config +6. Deployment storage backend account via Terraform +7. Create Azure DevOps project via Terraform + + + +## TODO / Rember +AzureAD +Exporse the Vault container on DevOps with a firewall rule on public ip +Add LoadBalancer with PIP for container access +Add NSG to the PIP, Nic or Container + diff --git a/packer/vmware/scripts/windows/windows-prepare.ps1 b/packer/vmware/scripts/windows/windows-prepare.ps1 index d99b965..87f5a08 100644 --- a/packer/vmware/scripts/windows/windows-prepare.ps1 +++ b/packer/vmware/scripts/windows/windows-prepare.ps1 @@ -36,6 +36,12 @@ Write-Output "Disabling system hibernation..." Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Power\" -Name "HiberFileSizePercent" -Value 0 | Out-Null Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Power\" -Name "HibernateEnabled" -Value 0 | Out-Null +# Set Power options +Powercfg /Change monitor-timeout-ac 0 +Powercfg /Change monitor-timeout-dc 0 +Powercfg /Change standby-timeout-ac 0 +Powercfg /Change standby-timeout-dc 0 + # Disable TLS 1.0.s Write-Output "Disabling TLS 1.0..." New-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" -Name "TLS 1.0" | Out-Null diff --git a/packer/vmware/windows/desktop/11/variables.pkr.hcl b/packer/vmware/windows/desktop/11/variables.pkr.hcl index 3a34d55..450cdec 100644 --- a/packer/vmware/windows/desktop/11/variables.pkr.hcl +++ b/packer/vmware/windows/desktop/11/variables.pkr.hcl @@ -284,11 +284,6 @@ variable "common_ovf_export_overwrite" { // Removable Media Settings -variable "iso_datastore" { - type = string - description = "The name of the source vSphere datastore for ISO images. (e.g. 'sfo-w01-cl01-nfs01')" -} - variable "iso_path" { type = string description = "The path on the source vSphere datastore for ISO image. (e.g. 'iso/windows')" diff --git a/packer/vmware/windows/desktop/11/windows-client.pkr.hcl b/packer/vmware/windows/desktop/11/windows-client.pkr.hcl index e94ae71..5cd7d51 100644 --- a/packer/vmware/windows/desktop/11/windows-client.pkr.hcl +++ b/packer/vmware/windows/desktop/11/windows-client.pkr.hcl @@ -36,7 +36,7 @@ locals { build_by = "Built by: HashiCorp Packer ${packer.version}" build_date = formatdate("YYYY-MM-DD hh:mm ZZZ", timestamp()) build_version = formatdate("YYMM", timestamp()) - iso_paths = ["[${var.iso_datastore}] ${var.iso_path}/${var.iso_file}", "[] /vmimages/tools-isoimages/${var.vm_guest_os_family}.iso"] + iso_paths = ["[] /vmimages/tools-isoimages/${var.vm_guest_os_family}.iso"] iso_checksum = "${var.iso_checksum_type}:${var.iso_checksum_value}" manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp()) manifest_path = "${path.cwd}/manifests/" @@ -87,6 +87,7 @@ source "vsphere-iso" "windows-desktop" { tools_upgrade_policy = var.common_tools_upgrade_policy // Removable Media Settings + iso_url = "${var.iso_path}/${var.iso_file}" iso_paths = local.iso_paths iso_checksum = local.iso_checksum diff --git a/terraform/vmware/infra/outputs.tf b/terraform/vmware/infra/outputs.tf index 87d973e..4c6e7dd 100644 --- a/terraform/vmware/infra/outputs.tf +++ b/terraform/vmware/infra/outputs.tf @@ -18,7 +18,7 @@ output "citrix_sf" { value = module.citrix_storefront[*].vm_info } -output "citrix_dc" { +output "citrix_ddc" { value = module.citrix_delivery_controller[*].vm_info } @@ -26,10 +26,18 @@ output "citrix_lic" { value = module.citrix_license_server[*].vm_info } +output "bots" { + value = module.bots[*].vm_info +} + output "vmware_hcs" { value = module.vmware_horizon[*].vm_info } +output "build" { + value = module.build[*].vm_info +} + output "vcsa" { value = nonsensitive(formatlist("%s ansible_host=%s", jsondecode(data.vault_kv_secret.vcsa.data_json).name, cidrhost(local.nic_cidr, jsondecode(data.vault_kv_secret.vcsa.data_json).ip))) } \ No newline at end of file diff --git a/terraform/vmware/infra/resource.tf b/terraform/vmware/infra/resource.tf index 12801c2..f0fbdeb 100644 --- a/terraform/vmware/infra/resource.tf +++ b/terraform/vmware/infra/resource.tf @@ -1,14 +1,18 @@ locals { template_windows_2022 = jsondecode(file("${var.root_path}/manifests/windows-server-2022-standard.json")) - + template_windows_11 = jsondecode(file("${var.root_path}/manifests/windows-desktop-11.json")) + + vsphere_server = cidrhost(jsondecode(data.vault_kv_secret.network.data_json).cidr ,jsondecode(data.vault_kv_secret.vcsa.data_json).ip) vsphere_user = jsondecode(data.vault_kv_secret.vcsa.data_json).user vsphere_password = jsondecode(data.vault_kv_secret.vcsa.data_json).password - + # Note, the first host will be used to the primary deployments vsphere_nic = jsondecode(data.vault_kv_secret.esxs[data.vault_kv_secrets_list.esx.names[0]].data_json).network vsphere_datastore = jsondecode(data.vault_kv_secret.esxs[data.vault_kv_secrets_list.esx.names[0]].data_json).datastore + vsphere_datastore_build = jsondecode(data.vault_kv_secret.esxs[data.vault_kv_secrets_list.esx.names[1]].data_json).datastore + domain = jsondecode(data.vault_kv_secret.domain.data_json).name build_password = jsondecode(data.vault_kv_secret.build.data_json).password @@ -236,4 +240,53 @@ module "vmware_horizon" { vsphere_datastore = local.vsphere_datastore vsphere_cluster = var.vsphere_cluster vsphere_source_template = local.template_windows_2022.builds[0].artifact_id +} + +module "bots" { + source = "./modules/vmware.vsphere.vm.windows" + + vsphere_server = local.vsphere_server + vsphere_user = local.vsphere_user + vsphere_password = local.vsphere_password + + vm_count = 10 + vm_name = "bot" + vm_cpu = 4 + vm_memory = 4096 + local_admin_password = local.build_password + domain = local.domain + domain_admin = var.domain_admin + domain_admin_password = random_password.password.result + + virtual_network_portgroup_name = local.vsphere_nic + + vsphere_datacenter = var.vsphere_datacenter + vsphere_datastore = local.vsphere_datastore + vsphere_cluster = var.vsphere_cluster + vsphere_source_template = local.template_windows_2022.builds[0].artifact_id +} + +module "build" { + source = "./modules/vmware.vsphere.vm.windows" + + vsphere_server = local.vsphere_server + vsphere_user = local.vsphere_user + vsphere_password = local.vsphere_password + + vm_count = 4 + vm_name = "build" + vm_cpu = 2 + vm_memory = 4096 + vm_guest_id = "windows9_64Guest" + local_admin_password = local.build_password + domain = local.domain + domain_admin = var.domain_admin + domain_admin_password = random_password.password.result + + virtual_network_portgroup_name = local.vsphere_nic + + vsphere_datacenter = var.vsphere_datacenter + vsphere_datastore = local.vsphere_datastore_build + vsphere_cluster = "Target" #var.vsphere_cluster + vsphere_source_template = local.template_windows_11.builds[0].artifact_id } \ No newline at end of file From ad9d22a5db639712e67bdf102d516a54ef5099ed Mon Sep 17 00:00:00 2001 From: Ryan Ververs-Bijkerk Date: Wed, 16 Aug 2023 08:25:19 +0200 Subject: [PATCH 4/5] GPO's --- ansible/roles/domain-controller/tasks/gpo.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ansible/roles/domain-controller/tasks/gpo.yml b/ansible/roles/domain-controller/tasks/gpo.yml index e7db897..4012df3 100644 --- a/ansible/roles/domain-controller/tasks/gpo.yml +++ b/ansible/roles/domain-controller/tasks/gpo.yml @@ -77,8 +77,8 @@ - { key: HKLM\Software\Policies\Microsoft\Windows\Windows Search, name: AllowCortanaAboveLock, type: DWORD, value: 0} - { key: HKLM\Software\Policies\Microsoft\Windows\Windows Search, name: DisableWebSearch, type: DWORD, value: 1} - { key: HKLM\Software\Policies\Microsoft\Windows\Windows Search, name: HideUNCTab, type: DWORD, value: 1} - - { key: HKLM\Software\Policies\Microsoft\Windows\Windows Search, name: ConnectedSearchUseWeb, type: DWORD, value: 0} - - { key: HKLM\Software\Policies\Microsoft\Windows\Windows Search, name: PreventIndexingOfflineFiles, type: DWORD, value: 1} + - { key: HKLM\Software\Policies\Microsoft\Windows\Windows Search, name: ConnectedSearchUseWeb, type: DWORD, value: 0} + - { key: HKLM\Software\Policies\Microsoft\Windows\Windows Search, name: PreventIndexingOfflineFiles, type: DWORD, value: 1} - { key: HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate, name: SetDisableUXWUAccess, type: DWORD, value: 1} - { key: HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU, name: AutoInstallMinorUpdates, type: DWORD, value: 1} - { key: HKLM\Software\Policies\Microsoft\WindowsMediaPlayer, name: GroupPrivacyAcceptance, type: DWORD, value: 1} @@ -88,6 +88,13 @@ - { key: HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer, name: ClearRecentProgForNewUserInStartMenu, type: DWORD, value: 1} - { key: HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer, name: NoInstrumentation, type: DWORD, value: 1} - { key: HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer, name: NoThumbnailCache, type: DWORD, value: 1} + - { key: HKCU\Software\Policies\Microsoft\office\16.0\common, name: sendcustomerdata, type: DWORD, value: 0} + - { key: HKCU\Software\Policies\Microsoft\office\16.0\common\general, name: shownfirstrunoptin, type: DWORD, value: 1} + - { key: HKCU\Software\Policies\Microsoft\office\16.0\common\privacy, name: controllerconnectedservicesenabled, type: DWORD, value: 2} + - { key: HKCU\Software\Policies\Microsoft\office\16.0\firstrun, name: bootedrtm, type: DWORD, value: 1} + - { key: HKCU\Software\Policies\Microsoft\office\16.0\firstrun, name: disablemovie, type: DWORD, value: 1} + - { key: HKCU\Software\Policies\Microsoft\office\16.0\teams, name: preventfirstlaunchafterinstall, type: DWORD, value: 1} + - { key: HKCU\Software\Policies\Microsoft\office\common\clienttelemetry, name: sendtelemetry, type: DWORD, value: 3} - { key: HKCU\Software\Policies\Microsoft\Windows\CloudContent, name: DisableWindowsSpotlightFeatures, type: DWORD, value: 1} - { key: HKCU\Software\Policies\Microsoft\Windows\CurrentVersion\PushNotifications, name: NoToastApplicationNotification, type: DWORD, value: 1} - { key: HKCU\Software\Policies\Microsoft\Windows\Directory UI, name: QueryLimit, type: DWORD, value: 1388} From b2a336ccf63c21370d6714208b62248743a6f867 Mon Sep 17 00:00:00 2001 From: Ryan Ververs-Bijkerk Date: Wed, 16 Aug 2023 08:30:47 +0200 Subject: [PATCH 5/5] Added missing pipeline --- terraform/devops/pipeline.tf | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/terraform/devops/pipeline.tf b/terraform/devops/pipeline.tf index 0f780f5..edb2c91 100644 --- a/terraform/devops/pipeline.tf +++ b/terraform/devops/pipeline.tf @@ -45,3 +45,31 @@ resource "azuredevops_build_definition" "image" { azuredevops_variable_group.lab.id ] } + +resource "azuredevops_build_definition" "build" { + project_id = azuredevops_project.project.id + name = "Build Deployment Pipeline" + ci_trigger { + use_yaml = false + } + + repository { + repo_type = "TfsGit" + repo_id = azuredevops_git_repository.repo.id + yml_path = ".devops/pipelines/vmware/build.yml" + } + + variable { + name = "pipeline_id" + value = azuredevops_build_definition.image.id + } + + variable { + name = "project_id" + value = azuredevops_project.project.id + } + + variable_groups = [ + azuredevops_variable_group.lab.id + ] +}