---
title: "PowerShell 的 try/catch 为什么漏掉了原生命令失败？"
date: 2026-11-13
slug: powershell-native-exit-codes
canonical: https://kernelranch.com/blog/2026/11/powershell-native-exit-codes
markdown_url: https://kernelranch.com/blog/2026/11/powershell-native-exit-codes.md
tags: ["powershell", "windows", "ci"]
---PowerShell 包装编译器、Git 或部署工具时，原生命令的非零退出码和 PowerShell 的异常处理取决于当前设置。需要精确解释工具退出码时，在调用后立即读取 `$LASTEXITCODE`，再按该工具的约定决定是否终止脚本。

## 1. 让同一条命令退出 7

把以下代码保存为 `native_exit_lab.ps1`，用 `pwsh -NoProfile -File ./native_exit_lab.ps1` 运行。需要 PowerShell 7.4 或更新版本和 Windows 的 `cmd.exe`。`/d` 禁止 cmd 执行自动运行命令。

```powershell
$ErrorActionPreference = 'Stop'

foreach ($nativePreference in @($false, $true)) {
    $PSNativeCommandUseErrorActionPreference = $nativePreference
    $caught = $false

    try {
        cmd.exe /d /c 'exit /b 7'
    } catch {
        $caught = $true
    }

    $code = $LASTEXITCODE
    if ($code -ne 7 -or $caught -ne $nativePreference) {
        throw "Unexpected state: preference=$nativePreference caught=$caught code=$code"
    }

    "preference=$nativePreference caught=$caught exit=$code"
}

$child = '$ErrorActionPreference="Stop"; $PSNativeCommandUseErrorActionPreference=$false; cmd.exe /d /c "exit /b 7"; exit $LASTEXITCODE'
$PSNativeCommandUseErrorActionPreference = $false
pwsh -NoProfile -Command $child
$propagated = $LASTEXITCODE
if ($propagated -ne 7) {
    throw "Child exit code was $propagated"
}
"child PowerShell exit=$propagated"
```

```text
preference=False caught=False exit=7
preference=True caught=True exit=7
child PowerShell exit=7
```

## 2. 明确谁解释退出码

当 `$PSNativeCommandUseErrorActionPreference` 为 true 时，非零退出会按 `$ErrorActionPreference` 处理。本例使用 `Stop`，因此进入 catch。设为 false 时，原生命令正常返回控制权，退出码仍由 `$LASTEXITCODE` 提供。后续另一条原生命令可能改写它，排障脚本应在调用后就保存。

有的工具用非零值表达差异或其他业务状态。包装这类工具时，可以在独立脚本块内将原生命令错误偏好设为 false，并根据工具文档解释每种返回值。可复用函数通常抛出异常或返回结构化结果，由脚本入口决定最终进程退出码。CI 若需要原样接收某个失败码，由入口执行 `exit $code`，并像样本一样从父进程验证。

## 小结

在原生命令调用处保存退出码，在脚本边界明确失败如何上报。`try/catch` 的表现要和偏好设置一起读。

## 数据来源与检索时间

| 来源 | URL | 检索日期 | 对应内容 |
|---|---|---|---|
| Microsoft Learn about_Automatic_Variables | https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-7.5#lastexitcode | 2026-11-13 | LASTEXITCODE 的来源及脚本退出行为 |
| Microsoft Learn about_Preference_Variables | https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.5#psnativecommanduseerroractionpreference | 2026-11-13 | 非零退出码如何遵循 ErrorActionPreference |

## 核验说明

- Windows、PowerShell 7.6.9 实测两种偏好设置与子进程退出码。示例使用确定性的 cmd 子进程，具体业务工具仍需按其退出码文档处理。
