Skip to content

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 specified at process spawn because ProcessLauncherFactory.Resolve(ScriptType.PowerShell) unconditionally returned PwshCoreProcessLauncher (which spawns pwsh.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.exe then PATH walk, all File.Exists — no process spawn, ~ms). New routing branch falls back to WindowsPowerShellProcessLauncher (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=true still 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.ps1 invocation 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.

Merge request reports

Loading