【问题标题】:Ignoring an errorlevel != 0 in Windows PowerShell (ISE)忽略 Windows PowerShell (ISE) 中的错误级别 != 0
【发布时间】:2010-11-26 12:23:56
【问题描述】:

我有一个运行外部 EXE 文件的脚本。当该 EXE 文件失败(将 errorlevel 设置为 1)时,PowerShell 脚本将失败。

我正在运行 curl.exe 并得到了这个:

  • CategoryInfo : NotSpecified: (% Total % ... Time Current:String) [], RemoteException + FullyQualifiedErrorId : NativeCommandError

如何忽略/捕获外部 EXE 文件的故障并继续执行我的脚本?

【问题讨论】:

  • 您确定是外部 EXE 返回导致 PowerShell 出错的错误代码吗?这通常不会导致在 PowerShell 中引发错误。实际上,您必须竭尽全力将表示错误的 $LASTEXITCODE 转换为 PowerShell 错误。
  • 你能至少发布一些代码吗?在这种情况下,通常失败不是默​​认行为。
  • 我正在运行 curl.exe 并得到这个:+ CategoryInfo : NotSpecified: ( % Total % ... Time Current:String) [], RemoteException + FullyQualifiedErrorId : NativeCommandError
  • 有趣。显然你正在通过 V2 Remoting 尝试这个?在这种情况下,本机命令似乎会导致 PowerShell 错误。我正在调查。
  • 我不熟悉 V2 远程处理。我正在尝试运行包含对 curl 的调用的本地脚本。

标签: powershell


【解决方案1】:

这与 EXE 返回的退出代码无关。当 EXE 写入 stderr 时会生成错误,但仅在 ISE 内或远程处理或使用后台作业时。

写入 stderr 的 EXE 不会从常规 PowerShell 命令提示符生成错误。我不知道为什么会这样。

【讨论】:

  • 在 shell 中,stderr 似乎直接进入控制台。尽管如果您将其重新路由到标准输出 (2>&1),它会将这些消息包装在 ErrorRecords 中。也许 PowerShell 团队认为 ISE 是一种所有错误都应该更明显的环境?
【解决方案2】:

实际上,应用程序运行良好 - PowerShell 错误地报告错误。

当应用程序打印到标准错误时,PowerShell 有时会得出应用程序失败的结论。这实际上是 PowerShell 开发人员做出的设计决定。恕我直言,这是一个错误,因为许多可靠的应用程序(例如 curl)在正常操作过程中会将有用的信息打印到标准错误中。结果是 PowerShell 只能与其他 PowerShell 脚本很好地配合使用,不能依赖它与其他应用程序进行互操作。


此线程中的其他读者难以重现该行为,因为 PowerShell 的实现方式不一致。 NativeCommandError 是否发生取决于标准错误的重定向方式(因此该错误发生在 vanilla PowerShell ISE 中,而不是 vanilla PowerShell 中)。

无论您对第一段中的设计决策有何看法,不一致的实现肯定是 PowerShell 错误 - 请参阅 $LastExitCode=0 but $?=False in PowerShell. Redirecting stderr to stdout gives NativeCommandError

【讨论】:

  • 如果curl在没有错误的情况下写standard error,那么结论肯定是curl和其他应用玩得不好,不能依赖与其他应用互操作。 PowerShell 将错误消息视为善意的错误消息,并不能证明 PowerShell 行为不端且不可靠。
  • @TessellatingHeckler:在 40 年左右的时间里,stderr 用于“不是常规输出,而是用户信息”。这允许将标准输出重定向到文件或其他程序,并且仍然可以看到日志输出。 stdlog 或其他东西会更好吗?是的。但我们被这个名字困住了。这是几十年来已知的行为。忽略这些知识并突然实施当前行为(以错误的方式)是Powershells的错误。对于实际报告错误,有一个东西叫做返回码......
  • 应用程序通过返回错误代码向调用者指示失败。假设仅基于写入 stderr 的失败是不正确的。
【解决方案3】:

我通过 PowerShell ISE(一个 IDE)运行脚本,我相信这是导致问题的原因。

似乎通过 PowerShell 本身运行它 上班。

【讨论】:

  • 是的,我发现了同样的事情......
【解决方案4】:

在将 stderr 重定向到 stdout 时,会出现原始帖子中提到的错误(“...NativeCommandError”),例如通过“...>file 2>&1”或“*>file”。如上所述,如果通过 stderr 输出某些内容,PowerShell 会产生此错误,即使该“某些内容”只是普通日志(没有错误)。 “CMake”例如使用 stderr 作为正常的跟踪输出流。虽然旧的 Windows 命令 shell/脚本不会将 stderr 上的任何内容解释为错误的证据,但如果使用“Invoke-Expression”调用可执行文件(例如 CMake)或直接调用,PowerShell 会。

但是!...如果使用“Start-Process”调用可执行文件,则不会发生同样的问题。

具体来说,案例1:

Invoke-Expression cmake .... 1>$logFile1 2>$logFile2

Invoke-Expression cmake .... *>$logFile

这会导致上面的错误

案例 2:

Start-Process cmake -ArgumentList $arguments ... -RedirectStandardOutput $logFile1 -RedirectStandardError $logFile2

错误没有出现。这些文件是“干净的”,但填充了两个输出文件

结论:根据调用可执行文件的方式,PowerShell 的行为会有所不同

Powershell 最好表现得像(旧的)Windows 命令 shell,因为可执行文件已经存在并且需要在不遇到此类问题的情况下运行。退出代码应该足以满足限定错误。如果这真的不可能,PowerShell 的这个特性——通过 stderr 将任何东西解释为错误——应该是可切换的。最后但同样重要的是,最好避免这方面的不一致行为,以及调用可执行文件的不同方法之间的不一致。

如果您不喜欢在“Start-Process”的情况下将流式传输到两个单独的文件中,则可行的解决方案是通过使用“cmd /c”在旧的命令外壳上下文中调用可执行文件在 PowerShell 脚本中。然后,您将 stdout 和 stderr 都流式传输到一个文件中,并在可执行文件运行时由两个流正确填充(即交错)。示例:

cmd /c "cmake ... >$logFile 2>&1"

【讨论】:

  • 我开始认为 cmd 的时代已经结束,然后在经历了这个惊人的怪癖之后我正在阅读这篇文章。谢谢你的笑声
【解决方案5】:

由于 Powershell 和 Powershell ISE 有不同的处理和处理错误输出的方式,我发现在我们的环境中最好的方法是使用旧的 Windows cmd.exe 使用命令执行包装器,如下所示:

$output = $(cmd /c "<<your exe here with parameters>>  2>&1")

此方法不需要将输出捕获到文件中。

进程完成后,错误状态会在 PowerShell 变量中显示:

$LASTEXITCODE

【讨论】:

    【解决方案6】:

    示例脚本:

    echo top
    cmd /c dir foo   # doesn't exist
    echo bottom
    

    如果通过 ISE、invoke-command、start-job 或 start-threadjob 运行,写入标准错误的任何内容都会生成远程异常。但脚本将继续运行。这仅适用于 Powershell 5。

    top
     Volume in drive C is DISK
     Volume Serial Number is 0123-4567
    
     Directory of C:\Users\js
    
    cmd : File Not Found
    At C:\Users\js\script.ps1:2 char:1
    + cmd /c dir foo 2>&1
    + ~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (File Not Found:String) [], RemoteException
        + FullyQualifiedErrorId : NativeCommandError
    
    bottom
    

    一种选择是使用 2>$null

    隐藏错误
    echo top
    cmd /c dir foo 2>$null
    echo bottom
    

    导致:

    top
     Volume in drive C is DISK
     Volume Serial Number is 0123-4567
    
     Directory of C:\Users\js
    
    bottom
    

    【讨论】:

      猜你喜欢
      • 2018-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-16
      • 2015-03-07
      • 2013-10-02
      • 2012-01-10
      • 2015-01-08
      相关资源
      最近更新 更多