fix(windows): detect Windows PowerShell in the Night Light script - #742
Conversation
The Night Light script guarded on $IsWindows, which only exists in PowerShell Core. Chezmoi runs .ps1 scripts with `powershell` (Windows PowerShell 5.1, PSEdition "Desktop") per the ps1 interpreter in .chezmoi.yaml.tmpl, where the variable is undefined. The negated guard was therefore always true and the script skipped itself on the exact platform it targets, printing "[SKIP] Night Light is a Windows-only setting." Replaces the guard with Test-WindowsHost, which treats PSEdition "Desktop" as Windows and otherwise falls back to $IsWindows. The rest of the script was already 5.1-compatible; verified the codec still round-trips the live registry blobs byte for byte under 5.1. Adds regression coverage: the script must not negate $IsWindows directly, and Test-WindowsHost plus a full script run are exercised in a real Windows PowerShell 5.1 child process. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixing the $IsWindows guard made the script actually run on Windows CI runners, where it then failed the whole chezmoi apply: a fresh machine has never used Night Light, so the CloudStore values do not exist and the script threw "Night Light settings are not initialised". The script now seeds a baseline instead of throwing. Sunset and sunrise are deliberately left unset: Windows derives them from the machine location, and seeding them would risk storing wrong times. With no solar window known, the state value is left off rather than forced on. Verified on a live Windows 11 install by backing up both blobs, deleting the keys, and writing a from-scratch payload: Windows accepts and retains it. The original settings were restored afterwards. Renames the helper to Get-NightLightDefaultSetting to satisfy PSScriptAnalyzer (PSUseShouldProcessForStateChangingFunctions, PSUseSingularNouns) and to match the Get-WindowsPersonalizationSetting convention in the sibling script. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Second failure found and fixedFixing the Test Windows Coder Install (Root) and Test Windows Light Installation run
FixIt now seeds a baseline instead of throwing. Sunset and sunrise are deliberately left unset — Windows derives them from the machine location, and seeding them would risk storing wrong times. With no solar window known, the state value is left off rather than forced on. Verified on real hardware, not just mocksBacked up both live blobs, deleted the keys, and wrote a from-scratch payload: Windows accepts and retains the shorter payload without rejecting or rewriting it. Original settings were restored afterwards and re-verified (sunset 21:06, sunrise 06:25, 3850 K, on). One incidental discovery worth recording: deleting the keys while logged in causes the shell to immediately rewrite them from memory with a fresh timestamp and an identical payload. These values are actively owned by the running shell, which is why preserving unknown fields on decode matters. AlsoRenamed the helper to Night Light suite: 70 tests. Full suite: 861 passed, 0 failed. Analyzer clean. |
Follow-up to #738.
Symptom
Running
chezmoi applyon Windows printed:...on Windows.
Cause
The script guarded with
if (-not $IsWindows).$IsWindowsis an automatic variable that only exists in PowerShell Core — it is undefined in Windows PowerShell 5.1, so it evaluates to$nulland the negated guard is always$true.And
.chezmoi.yaml.tmplpins exactly that interpreter:Confirmed locally:
So the script skipped itself on the only platform it targets. It worked when I tested it during development because I invoked it from
pwsh7.Fix
Adds
Test-WindowsHost, which treatsPSEdition -eq "Desktop"as Windows (Desktop edition only ships on Windows) and otherwise falls back to$IsWindowsviaGet-Variable -ErrorAction SilentlyContinue.The rest of the script was already 5.1-compatible — no PS7-only syntax — verified by round-tripping the live registry blobs byte for byte under 5.1.
Verification
Regression coverage
New
Windows host detectionblock (4 tests):Test-WindowsHostreturns true on the current host$IsWindowsdirectlyTest-WindowsHostreturnsTrueinside a realpowershell.exe5.1 child processWindows-only settingNight Light suite: 66 passed. Full Pester suite: 857 passed, 0 failed. PSScriptAnalyzer clean.
Note for later (not in this PR)
home/dot_config/powershell/scripts/Sign-PowerShellScripts.ps1andNew-SigningCert.ps1.tmpluse the same-not $IsWindowspattern. They are invoked manually underpwsh7 so they are not currently broken, but they would misbehave if ever run under Windows PowerShell.