--- - name: Enable required Windows features for WSL tags: [packages, services, wsl] ansible.windows.win_optional_feature: name: - Microsoft-Windows-Subsystem-Linux - VirtualMachinePlatform state: present include_parent: true - name: Gather Windows host version details tags: [packages] ansible.windows.win_powershell: script: | $os = Get-ComputerInfo $buildNumber = [int]$os.OsBuildNumber $Ansible.Result = @{ product_name = $os.WindowsProductName build_number = $buildNumber is_windows_11 = $buildNumber -ge 22000 } $Ansible.Changed = $false register: windows_host_version_state - name: Fail when Windows host is not Windows 11 tags: [packages] ansible.builtin.fail: msg: >- workstation_host_windows is supported only on Windows 11. Detected {{ windows_host_version_state.result.product_name }} build {{ windows_host_version_state.result.build_number }}. when: not (windows_host_version_state.result.is_windows_11 | default(false)) - name: Enable dark mode for Windows apps tags: [packages] ansible.windows.win_regedit: path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize name: AppsUseLightTheme data: 0 type: dword register: windows_apps_dark_mode_state when: windows_enable_dark_theme | default(false) - name: Enable dark mode for Windows system surfaces tags: [packages] ansible.windows.win_regedit: path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize name: SystemUsesLightTheme data: 0 type: dword register: windows_system_dark_mode_state when: windows_enable_dark_theme | default(false) - name: Hide Windows taskbar search box tags: [packages] ansible.windows.win_regedit: path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Search name: SearchboxTaskbarMode data: 0 type: dword register: windows_taskbar_search_state when: windows_hide_taskbar_search | default(false) - name: Hide Windows 11 taskbar widgets tags: [packages] ansible.windows.win_regedit: path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced name: TaskbarDa data: 0 type: dword register: windows_11_widgets_state when: windows_hide_taskbar_widgets | default(false) - name: Disable Windows 11 widgets via policy tags: [packages] ansible.windows.win_regedit: path: HKLM:\SOFTWARE\Policies\Microsoft\Dsh name: AllowNewsAndInterests data: 0 type: dword register: windows_11_widgets_policy_state when: windows_hide_taskbar_widgets | default(false) - name: Note when Windows shell settings may require sign out tags: [packages] ansible.builtin.debug: msg: >- Windows shell appearance settings changed. Sign out and back in, or restart explorer.exe, if taskbar or theme updates do not appear immediately. Windows 11 widget policy changes can require signing out before the widget button disappears from the taskbar. changed_when: false when: >- (windows_apps_dark_mode_state is changed) or (windows_system_dark_mode_state is changed) or (windows_taskbar_search_state is changed) or (windows_11_widgets_state is changed) or (windows_11_widgets_policy_state is changed) - name: Ensure winget is available on Windows host tags: [packages] ansible.windows.win_powershell: script: | $winget = Get-Command winget.exe -ErrorAction SilentlyContinue if ($null -eq $winget) { throw 'winget.exe is not available on the Windows host. Install App Installer or rerun the bootstrap script.' } $Ansible.Changed = $false - name: Ensure WSL 2 is the default backend tags: [packages, services, wsl] ansible.windows.win_powershell: script: | $status = & wsl --status 2>$null if ($LASTEXITCODE -eq 0 -and $status -match 'Default Version:\s*2') { $Ansible.Changed = $false return } & wsl --set-default-version 2 if ($LASTEXITCODE -ne 0) { throw 'Failed to set WSL default version to 2.' } $Ansible.Changed = $true - name: Install Windows workstation applications with winget tags: [packages] ansible.windows.win_powershell: script: | $packageId = '{{ item.id }}' $packageName = '{{ item.name | default(item.id) }}' $installed = & winget list --id $packageId --exact --accept-source-agreements --disable-interactivity 2>$null if ($LASTEXITCODE -eq 0 -and $installed -match [regex]::Escape($packageId)) { $Ansible.Changed = $false return } & winget install --id $packageId --exact --silent --accept-package-agreements --accept-source-agreements --disable-interactivity if ($LASTEXITCODE -ne 0) { throw "Failed to install $packageName with winget" } $Ansible.Changed = $true loop: "{{ windows_winget_packages | default([]) }}" loop_control: label: "{{ item.id }}" - name: Install VS Code WSL extensions on Windows host tags: [packages, vscode] ansible.windows.win_powershell: script: | $extensionId = '{{ item }}' $code = Get-Command code.cmd -ErrorAction SilentlyContinue if ($null -eq $code) { throw 'code.cmd is not available. Ensure Visual Studio Code is installed before managing extensions.' } $installedExtensions = & $code.Source --list-extensions if ($installedExtensions -contains $extensionId) { $Ansible.Changed = $false return } & $code.Source --install-extension $extensionId --force if ($LASTEXITCODE -ne 0) { throw "Failed to install VS Code extension $extensionId" } $Ansible.Changed = $true loop: "{{ windows_vscode_extensions | default([]) }}" loop_control: label: "{{ item }}"