PowerShell 7 调用外部程序:如何避免忽略非零退出码
自动化脚本里,外部程序失败后不应继续执行依赖它的步骤。一个容易忽略的区别是:在下面的设置下,$ErrorActionPreference = 'Stop' 并不会自动把原生程序的非零退出码变成可被 catch 捕获的错误。
以下实验在 Windows 11、PowerShell 7.6.7 本机运行。复制整段到 PowerShell 7 执行;它启动本机 pwsh 子进程,分别以 7 和 0 退出,既不联网也不读写测试文件。
Invoke-Command -ScriptBlock {
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $false
# 错误示范:Stop 不等于自动捕获原生程序的非零退出码。
try {
pwsh -NoLogo -NoProfile -NonInteractive -Command 'exit 7'
"naive: continued, code=$LASTEXITCODE"
} catch {
'naive: caught'
}
# $? 必须及时保存;普通成功命令不会覆盖 $LASTEXITCODE。
pwsh -NoLogo -NoProfile -NonInteractive -Command 'exit 7'
$immediate = $?
Write-Output 'intermediate: log ok'
$afterLog = $?
$afterLogCode = $LASTEXITCODE
"status: immediate=$immediate after-log=$afterLog code=$afterLogCode"
# 先保存退出码,再决定是否执行后续步骤。
foreach ($code in 7, 0) {
try {
pwsh -NoLogo -NoProfile -NonInteractive -Command "exit $code"
$exitCode = $LASTEXITCODE
"test: code=$exitCode"
if ($exitCode -ne 0) { throw "native exit $exitCode" }
'next step: runs'
} catch {
"next step: blocked ($($_.Exception.Message))"
}
}
}
本机实际输出:
naive: continued, code=7
intermediate: log ok
status: immediate=False after-log=True code=7
test: code=7
next step: blocked (native exit 7)
test: code=0
next step: runs
第一行说明退出码为 7 时,脚本仍越过了 catch。第二次运行失败后,$? 立即是 False;成功执行 Write-Output 后,它变成 True。此时 $LASTEXITCODE 仍是 7。第三部分显式保存退出码:7 会触发异常、跳过模拟的后续步骤;0 会继续执行。示例的后续步骤只是打印文字,没有部署或修改文件。
实际使用时,紧接外部程序保存 $LASTEXITCODE,再按该程序的约定判断。不要一律假设所有非零值都代表同一种错误;也不要在检查前调用另一个原生程序,否则可能读到后者的退出码。如果程序本身无法启动,还需另外处理启动错误。
本例显式将 $PSNativeCommandUseErrorActionPreference 设为 false,因此结论对应此设置;设为 true 时非零退出码会参与 PowerShell 错误处理,行为还受错误首选项影响。示例里的 catch 只为同时展示两种结果,生产脚本不能仅打印错误然后继续成功退出:应在入口处理异常,返回非零进程退出码,并跳过依赖的操作。
本文由 Hermes AI 协助编写,代码和输出均在本机实际测试。
- 点赞
- 收藏
- 关注作者
评论(0)