我有一个运行外部EXE文件的脚本。当该EXE文件失败时(将errorlevel设置为1),PowerShell脚本将失败。
我正在运行curl.exe并且得到了这个:
- CategoryInfo:NotSpecified:(%Total%... Time Current:String)[],RemoteException + FullyQualifiedErrorId:NativeCommandError
如何忽略/捕获外部EXE文件的失败并继续我的脚本?
答案 0 :(得分:19)
这与EXE返回的退出代码无关。 EXE写入stderr时会生成错误,但仅在ISE内或远程处理或使用后台作业时生成错误。
写入stderr的EXE会使不从常规PowerShell命令提示符生成错误。我不确定为什么会这样。
答案 1 :(得分:15)
实际上,应用程序运行良好 - PowerShell在报告错误时出错。
当应用程序打印到标准错误时,PowerShell有时会认为该应用程序已失败。这实际上是PowerShell开发人员做出的设计决策。恕我直言,这是一个错误,因为许多可靠的应用程序(如卷曲)在正常操作过程中将有用信息打印到标准错误。结果是PowerShell只能与其他PowerShell脚本很好地兼容,并且不能依赖它与其他应用程序进行互操作。
此线程中的其他读者难以重现行为,因为PowerShell不一致地实现它。是否发生NativeCommandError取决于标准错误的重定向方式(因此,错误发生在vanilla PowerShell ISE中,而不是vanilla PowerShell)。
无论您对第一段中的设计决策有什么看法,不一致的实现都是针对某些PowerShell错误的 - 请参阅 $LastExitCode=0 but $?=False in PowerShell. Redirecting stderr to stdout gives NativeCommandError 。
答案 2 :(得分:1)
我是通过PowerShell ISE(IDE)运行脚本的,我相信这就是造成这些问题的原因。
似乎通过PowerShell运行它 工作。
答案 3 :(得分:0)
将stderr重定向到stdout时,出现原始帖子(“ ... NativeCommandError”)中提到的错误,例如通过“ ...>文件2>&1”或“ *>文件”。如上所述,如果通过stderr输出了某些内容,即使该“内容”只是普通日志(没有错误),PowerShell也会产生此错误。 “ CMake”,例如使用stderr作为常规跟踪输出流。旧的Windows Command Shell /脚本不会将stderr上的任何内容解释为错误的证据,而如果可执行文件(例如CMake)是通过“ Invoke-Expression”调用或直接调用的,则PowerShell会这样做。
但是!...如果使用“启动进程”调用可执行文件,则不会发生相同的问题。
具体情况一:
Invoke-Expression cmake .... 1>$logFile1 2>$logFile2
OR
Invoke-Expression cmake .... *>$logFile
这会导致上述错误
情况2:
Start-Process cmake -ArgumentList $arguments ... -RedirectStandardOutput $logFile1 -RedirectStandardError $logFile2
未出现错误。文件是“干净的”,但已填充两个输出文件
结论:PowerShell的行为取决于可执行文件的调用方式
鉴于现有的可执行文件必须在运行时不会遇到此类问题,因此Powershell的行为应类似于(旧的)Windows命令外壳。希望退出代码能够满足限定错误的要求。如果确实不可能,那么PowerShell的此功能-通过stderr将任何内容解释为错误-应该可以切换。最后但并非最不重要的一点是,最好避免在这方面的行为不一致以及在调用可执行文件的不同方式之间。
如果您不喜欢在“启动过程”的情况下建议流入两个单独的文件,则可行的解决方案是使用“ cmd / c”在旧命令外壳程序上下文中调用可执行文件在PowerShell脚本中。然后,将stdout和stderr都流式传输到一个文件中,并在可执行文件运行时由两个流正确填充(即交织)。示例:
cmd /c "cmake ... >$logFile 2>&1"
答案 4 :(得分:0)
示例脚本:
SELECT t1.id
FROM (
SELECT MAX(t1.value) AS max_value
FROM Table2 t2
JOIN Table1 t1 ON t1.id = t2.id
) t
JOIN Table1 t1 ON t1.value = t.max_value
JOIN Table2 t2 ON t2.id = t1.id
如果通过ISE,invoke-command,start-job或start-threadjob运行,则写入标准错误的任何内容都会生成远程异常。但是该脚本将继续运行。这仅适用于Powershell 5。
id
1
3
一种选择是使用2> $ null
隐藏错误echo top
cmd /c dir foo # doesn't exist
echo bottom
结果:
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
答案 5 :(得分:0)
由于Powershell和Powershell ISE具有不同的处理和处理错误输出的方式,因此我发现我们环境中的最佳方法是使用旧Windows cmd.exe使用命令执行包装,如下所示:
$output = $(cmd /c "<<your exe here with parameters>> 2>&1")
此方法不需要将输出捕获到文件中。
该过程完成后,PowerShell变量中将提供错误状态:
$LASTEXITCODE