Fall back to Windows PowerShell when pwsh-Core not installed
Summary
- Fix operator-visible crash on Windows tentacles without PowerShell 7 installed: every PowerShell dispatch (upgrade, deployment, health check) hit
Win32Exception (2): system cannot find the file specifiedat process spawn becauseProcessLauncherFactory.Resolve(ScriptType.PowerShell)unconditionally returnedPwshCoreProcessLauncher(which spawnspwsh.exe). PS7 is OPTIONAL on Windows — Microsoft does NOT ship it with the OS — so this stranded every stock Windows host. - Add
PwshAvailableProbe(swappable seam) +DefaultPwshAvailable()(production probe: canonical MSI install path at%ProgramFiles%\PowerShell\7\pwsh.exethen PATH walk, allFile.Exists— no process spawn, ~ms). New routing branch falls back toWindowsPowerShellProcessLauncher(OS-bundled PS 5.1, always present on Windows Server 2016+ / Win10 1607+) when the probe returns false. - Operator opt-in via
SQUID_TENTACLE_USE_WINDOWS_POWERSHELL=truestill wins over the probe (operators with legacy WMI / older AD modules get deterministic 5.1 routing regardless of PS7 install state).
Routing precedence (Windows)
| # | Condition | Launcher |
|---|---|---|
| 1 | Opt-in env var truthy |
WindowsPowerShellProcessLauncher (5.1) |
| 2 | pwsh.exe resolvable |
PwshCoreProcessLauncher (7+, UTF-8 stdout) |
| 3 | pwsh.exe NOT resolvable |
WindowsPowerShellProcessLauncher (5.1, the fix) |
Linux / macOS always route to PwshCoreProcessLauncher — the probe is a no-op off-Windows because PS 5.1 doesn't exist there.
Test plan
-
Truth-table tests covering all four cross-platform routing cells (Windows + pwsh present / Windows + pwsh missing / Windows + opt-in beats probe / non-Windows probe inert) -
DefaultPwshAvailable()sanity test: returns a bool without throwing on every platform -
Focused tests: 44/44 in Squid.Tentacle.Tests.Platform.ProcessLauncherTests -
Unit suite: 5517/5517 in Squid.UnitTests -
Operator-side: redeploy the agent, retry upgrade — expect Win32Exception (2) gone; PowerShell.exe -NoProfile -NoLogo -NonInteractive -ExecutionPolicy Unrestricted -File script.ps1invocation succeeds
Operator's failure mode this fixes
Server exception: Win32Exception (2): An error occurred trying to start process 'pwsh'
with working directory 'C:\Windows\TEMP\squid-tentacle-upgrade-23-...'.
系统找不到指定的文件。
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at Squid.Tentacle.ScriptExecution.LocalScriptService.StartViaLauncher(...)
at Squid.Tentacle.ScriptExecution.LocalScriptService.StartProcess(...)
After this PR: agent transparently uses PowerShell.exe 5.1 → process spawns → upgrade runs.
Why not change the default?
The comment block on Resolve (preserved + extended in this PR) documents the reason pwsh-Core is preferred on Windows: it writes UTF-8 stdout, so cross-locale non-ASCII output (中文 / emoji / accented chars) round-trips correctly through the redirect pipe. Windows PowerShell 5.1 writes OEM bytes which the dedicated WindowsPowerShellProcessLauncher decodes correctly via OEMCodePage, but that only works for ASCII + locale-matching characters. For operators who install PS7, the better path stays the default. The fallback is a safety net for the OOTB case.