Simplify Windows role to Windows 11 only

This commit is contained in:
Fabio Scotto di Santolo
2026-04-02 16:12:40 +02:00
parent df3aa5abeb
commit a38e16556e
3 changed files with 56 additions and 32 deletions

View File

@@ -18,7 +18,7 @@ Project type: Ansible-driven infrastructure, workstation/server provisioning, an
- Void desktops: `ikaros`, `nymph` - Void desktops: `ikaros`, `nymph`
- Ubuntu workstation: `deadalus` - Ubuntu workstation: `deadalus`
- Ubuntu server: `prometheus` - Ubuntu server: `prometheus`
- Workstation topology now supports Linux host + Ubuntu dev and Windows host + Ubuntu WSL dev as separate layers - Workstation topology now supports Linux host + Ubuntu dev and Windows 11 host + Ubuntu WSL dev as separate layers
- The WSL dev environment is intended to be managed by running Ansible locally from inside the distro, while the Windows host is managed remotely via PSRP - The WSL dev environment is intended to be managed by running Ansible locally from inside the distro, while the Windows host is managed remotely via PSRP
- Most hosts use `ansible_connection: local` - Most hosts use `ansible_connection: local`
- Current playbook layering: `all:!workstation_host_windows -> dotfiles_common`, `void -> packages_void + services_runit + profile_desktop_common + profile_desktop_i3 + profile_desktop_sway + profile_desktop_hyprland + profile_desktop_host`, `workstation_dev_ubuntu -> packages_ubuntu + services_systemd + profile_workstation_dev_common`, `workstation_host_linux -> profile_workstation_gnome`, `workstation_dev_wsl -> packages_ubuntu + services_systemd + profile_workstation_dev_common + profile_workstation_dev_wsl`, `workstation_host_windows -> profile_workstation_host_windows`, `ubuntu_server -> packages_ubuntu + services_systemd + profile_server` - Current playbook layering: `all:!workstation_host_windows -> dotfiles_common`, `void -> packages_void + services_runit + profile_desktop_common + profile_desktop_i3 + profile_desktop_sway + profile_desktop_hyprland + profile_desktop_host`, `workstation_dev_ubuntu -> packages_ubuntu + services_systemd + profile_workstation_dev_common`, `workstation_host_linux -> profile_workstation_gnome`, `workstation_dev_wsl -> packages_ubuntu + services_systemd + profile_workstation_dev_common + profile_workstation_dev_wsl`, `workstation_host_windows -> profile_workstation_host_windows`, `ubuntu_server -> packages_ubuntu + services_systemd + profile_server`
@@ -156,7 +156,7 @@ Use the narrowest command matching the changed area.
- `profile_workstation_dev_common` carries the Ubuntu dev layer shared by native workstation and WSL Ubuntu - `profile_workstation_dev_common` carries the Ubuntu dev layer shared by native workstation and WSL Ubuntu
- `profile_workstation_gnome` carries Linux host-only GNOME setup, extensions, and UFW - `profile_workstation_gnome` carries Linux host-only GNOME setup, extensions, and UFW
- `profile_workstation_dev_wsl` carries WSL-specific Ubuntu tweaks such as `systemd` and PSRP Python dependencies - `profile_workstation_dev_wsl` carries WSL-specific Ubuntu tweaks such as `systemd` and PSRP Python dependencies
- `profile_workstation_host_windows` manages the Windows host via PSRP over HTTPS using `negotiate` by default and installs host applications via `winget` - `profile_workstation_host_windows` manages the Windows 11 host via PSRP over HTTPS using `negotiate` by default and installs host applications via `winget`
- `deadalus-wsl` is modeled as a local inventory target intended to be run from inside the Ubuntu WSL distro - `deadalus-wsl` is modeled as a local inventory target intended to be run from inside the Ubuntu WSL distro
- Future Windows taskbar pinning work should be done from a real Windows session after discovering installed app identifiers on that host, then applied via a Windows 11 taskbar layout policy with `PinListPlacement="Replace"` - Future Windows taskbar pinning work should be done from a real Windows session after discovering installed app identifiers on that host, then applied via a Windows 11 taskbar layout policy with `PinListPlacement="Replace"`
- Do not auto-restart `emptty` during playbook runs on active desktop hosts; prefer a manual restart from SSH or another TTY after the run - Do not auto-restart `emptty` during playbook runs on active desktop hosts; prefer a manual restart from SSH or another TTY after the run

View File

@@ -96,7 +96,7 @@ Lo stato attuale del profilo desktop include, tra le altre cose:
Sistemi operativi supportati: Sistemi operativi supportati:
- Ubuntu LTS nativa - Ubuntu LTS nativa
- Windows host + Ubuntu WSL - Windows 11 host + Ubuntu WSL
Desktop environment host Linux: Desktop environment host Linux:
@@ -113,7 +113,7 @@ Il profilo workstation e agganciato al playbook principale e ora distingue:
- layer dev Ubuntu condiviso tra workstation Linux nativa e Ubuntu in WSL - layer dev Ubuntu condiviso tra workstation Linux nativa e Ubuntu in WSL
- layer host Linux GNOME - layer host Linux GNOME
- layer host Windows con bootstrap WSL, remoting `PSRP` su `HTTPS/5986`, gestione app via `winget` e VS Code lato Windows - layer host Windows 11 con bootstrap WSL, remoting `PSRP` su `HTTPS/5986`, gestione app via `winget` e VS Code lato Windows
- layer WSL dedicato per sviluppo con `systemd` - layer WSL dedicato per sviluppo con `systemd`
Lo stato attuale del profilo workstation include: Lo stato attuale del profilo workstation include:

View File

@@ -16,14 +16,20 @@
$buildNumber = [int]$os.OsBuildNumber $buildNumber = [int]$os.OsBuildNumber
$Ansible.Result = @{ $Ansible.Result = @{
product_name = $os.WindowsProductName product_name = $os.WindowsProductName
version = $os.WindowsVersion
build_number = $buildNumber build_number = $buildNumber
is_windows_11 = ($os.WindowsProductName -like 'Windows 11*') -or ($buildNumber -ge 22000) is_windows_11 = $buildNumber -ge 22000
is_windows_10 = ($os.WindowsProductName -like 'Windows 10*') -and ($buildNumber -lt 22000)
} }
$Ansible.Changed = $false $Ansible.Changed = $false
register: windows_host_version_state 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 - name: Enable dark mode for Windows apps
tags: [packages] tags: [packages]
ansible.windows.win_regedit: ansible.windows.win_regedit:
@@ -62,9 +68,7 @@
data: 0 data: 0
type: dword type: dword
register: windows_11_widgets_state register: windows_11_widgets_state
when: when: windows_hide_taskbar_widgets | default(false)
- windows_hide_taskbar_widgets | default(false)
- windows_host_version_state.result.is_windows_11 | default(false)
- name: Disable Windows 11 widgets via policy - name: Disable Windows 11 widgets via policy
tags: [packages] tags: [packages]
@@ -74,21 +78,7 @@
data: 0 data: 0
type: dword type: dword
register: windows_11_widgets_policy_state register: windows_11_widgets_policy_state
when: when: windows_hide_taskbar_widgets | default(false)
- windows_hide_taskbar_widgets | default(false)
- windows_host_version_state.result.is_windows_11 | default(false)
- name: Hide Windows 10 news and interests taskbar widget
tags: [packages]
ansible.windows.win_regedit:
path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Feeds
name: ShellFeedsTaskbarViewMode
data: 2
type: dword
register: windows_10_widgets_state
when:
- windows_hide_taskbar_widgets | default(false)
- windows_host_version_state.result.is_windows_10 | default(false)
- name: Note when Windows shell settings may require sign out - name: Note when Windows shell settings may require sign out
tags: [packages] tags: [packages]
@@ -104,7 +94,6 @@
or (windows_taskbar_search_state is changed) or (windows_taskbar_search_state is changed)
or (windows_11_widgets_state is changed) or (windows_11_widgets_state is changed)
or (windows_11_widgets_policy_state is changed) or (windows_11_widgets_policy_state is changed)
or (windows_10_widgets_state is changed)
- name: Ensure winget is available on Windows host - name: Ensure winget is available on Windows host
tags: [packages] tags: [packages]
@@ -140,6 +129,7 @@
$packageId = '{{ item.id }}' $packageId = '{{ item.id }}'
$packageName = '{{ item.name | default(item.id) }}' $packageName = '{{ item.name | default(item.id) }}'
$packageScope = '{{ item.scope | default('' ) }}' $packageScope = '{{ item.scope | default('' ) }}'
$packageIdRegex = [regex]::Escape($packageId)
$installArgs = @( $installArgs = @(
'install' 'install'
'--id', $packageId '--id', $packageId
@@ -154,10 +144,12 @@
$installArgs += @('--scope', $packageScope) $installArgs += @('--scope', $packageScope)
} }
$installed = & winget list --id $packageId --exact --accept-source-agreements --disable-interactivity 2>$null if ($packageScope -ne 'user') {
if ($LASTEXITCODE -eq 0 -and $installed -match [regex]::Escape($packageId)) { $installed = & winget list --id $packageId --exact --accept-source-agreements --disable-interactivity 2>$null
$Ansible.Changed = $false if ($LASTEXITCODE -eq 0 -and $installed -match $packageIdRegex) {
return $Ansible.Changed = $false
return
}
} }
if ($packageScope -eq 'user') { if ($packageScope -eq 'user') {
@@ -170,11 +162,31 @@
$taskScriptPath = Join-Path $env:TEMP "$taskName.ps1" $taskScriptPath = Join-Path $env:TEMP "$taskName.ps1"
$stdoutPath = Join-Path $env:TEMP "$taskName.stdout.log" $stdoutPath = Join-Path $env:TEMP "$taskName.stdout.log"
$stderrPath = Join-Path $env:TEMP "$taskName.stderr.log" $stderrPath = Join-Path $env:TEMP "$taskName.stderr.log"
$resultPath = Join-Path $env:TEMP "$taskName.result.json"
$quotedArgs = ($installArgs | ForEach-Object { '"' + ($_ -replace '"', '""') + '"' }) -join ', ' $quotedArgs = ($installArgs | ForEach-Object { '"' + ($_ -replace '"', '""') + '"' }) -join ', '
$taskScript = @( $taskScript = @(
"`$ErrorActionPreference = 'Stop'",
"function Test-PackageInstalled {",
" `$installed = & winget.exe list --id '$packageId' --exact --accept-source-agreements --disable-interactivity 2>`$null",
" return (`$LASTEXITCODE -eq 0 -and `$installed -match '$packageIdRegex')",
"}",
"`$result = @{ changed = `$false; installed = `$false }",
"if (-not (Test-PackageInstalled)) {",
"`$installArgs = @($quotedArgs)", "`$installArgs = @($quotedArgs)",
"`$process = Start-Process -FilePath 'winget.exe' -ArgumentList `$installArgs -Wait -PassThru -NoNewWindow -RedirectStandardOutput '$stdoutPath' -RedirectStandardError '$stderrPath'", "`$process = Start-Process -FilePath 'winget.exe' -ArgumentList `$installArgs -Wait -PassThru -NoNewWindow -RedirectStandardOutput '$stdoutPath' -RedirectStandardError '$stderrPath'",
"exit `$process.ExitCode" " if (`$process.ExitCode -ne 0) { exit `$process.ExitCode }",
" `$deadline = (Get-Date).AddMinutes(2)",
" do {",
" Start-Sleep -Seconds 2",
" `$result.installed = Test-PackageInstalled",
" } while ((Get-Date) -lt `$deadline -and -not `$result.installed)",
" if (-not `$result.installed) { throw 'Package was not detected after the user-scoped install completed.' }",
" `$result.changed = `$true",
"}",
"else {",
" `$result.installed = `$true",
"}",
"`$result | ConvertTo-Json -Compress | Set-Content -Path '$resultPath' -Encoding Ascii"
) -join [Environment]::NewLine ) -join [Environment]::NewLine
Set-Content -Path $taskScriptPath -Value $taskScript -Encoding Ascii Set-Content -Path $taskScriptPath -Value $taskScript -Encoding Ascii
@@ -203,10 +215,22 @@
$stdout = if (Test-Path $stdoutPath) { Get-Content -Path $stdoutPath -Raw } else { '' } $stdout = if (Test-Path $stdoutPath) { Get-Content -Path $stdoutPath -Raw } else { '' }
throw "Failed to install $packageName with winget. Exit code: $($taskInfo.LastTaskResult). Stdout: $stdout Stderr: $stderr" throw "Failed to install $packageName with winget. Exit code: $($taskInfo.LastTaskResult). Stdout: $stdout Stderr: $stderr"
} }
if (-not (Test-Path $resultPath)) {
throw "Failed to install $packageName with winget: no result file was produced by the user-scoped scheduled task."
}
$result = Get-Content -Path $resultPath -Raw | ConvertFrom-Json
if (-not $result.installed) {
throw "Failed to install $packageName with winget: the package is still not detected after the user-scoped install task finished."
}
$Ansible.Changed = [bool]$result.changed
return
} }
finally { finally {
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
Remove-Item -Path $taskScriptPath, $stdoutPath, $stderrPath -Force -ErrorAction SilentlyContinue Remove-Item -Path $taskScriptPath, $stdoutPath, $stderrPath, $resultPath -Force -ErrorAction SilentlyContinue
} }
} }
else { else {