批处理文件中的退出代码不会传播到父级Powershell脚本

时间:2019-03-21 21:14:01

标签: powershell

请注意:

c:\ temp \ 1.cmd

@echo off
setlocal

cmd /c dir aaa
IF %ERRORLEVEL% NEQ 0 GOTO fail
GOTO end
:fail
echo - Script failed

:end
endlocal

现在,如果我在命令提示符下运行它:

C:\temp> cmd
Microsoft Windows [Version 10.0.16299.967]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\temp>c:\temp\1.cmd
 Volume in drive C has no label.
 Volume Serial Number is 4A5E-F223

 Directory of C:\temp

File Not Found
- Script failed

C:\temp>echo %errorlevel%
1

C:\temp>

现在我正在Powershell中运行它:

C:\temp> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.16299.967
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.16299.967
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


C:\temp> cmd /c C:\temp\1.cmd
 Volume in drive C has no label.
 Volume Serial Number is 4A5E-F223

 Directory of C:\temp

File Not Found
- Script failed
C:\temp> $LASTEXITCODE
0
C:\temp>

据我所知,退出代码应该正确传播。那是什么问题呢?

2 个答案:

答案 0 :(得分:3)

jazzdelightsme's effective solution提供一些背景信息

  • 执行批处理文件后, %ERRORLEVEL%在同一cmd.exe进程中反映该批处理文件的-隐式或显式-退出代码 执行了批处理文件。

    • 隐式退出代码是恰好由批处理文件退出之前执行的最后一个退出代码报告语句设置的代码。

    • 通过在批处理文件中调用 exit /b <n> 来设置 显式退出代码,以便通过退出给定的退出代码(<n>)。

  • 运行批处理文件的 cmd.exe进程(始终在进程中)仅将批处理文件的 explicit 退出代码传播为其进程退出代码,即仅当批处理文件使用exit /b 时。

    • help exit的措词有些混乱(也很有趣!“指定数字”),但可以解释为传达这一事实。

    • 也许的想法是,隐式退出代码(偶然设置)不会保证向外部世界传播作为总体成功/失败指标。

以上解释了您看到的行为:

  • cmd.exe运行时,在进程中运行批处理文件的该进程在%ERRORLEVEL% implicit 退出代码。 >

  • 相比之下, PowerShell必须在cmd.exe 子进程 中运行批处理文件,因此只能看到cmd.exe自己的文件如前所述,退出代码不反映批处理文件的隐式退出代码。

    • 从PowerShell 运行c:\temp\1.cmd 等同于从cmd /c c:\temp\1.cmd运行cmd.exe-您可以在两者中观察到相同的退出代码行为。

答案 1 :(得分:1)

首先:ERRORLEVEL is not %ERRORLEVEL%

第二,错误级别与进程退出代码不同。

尝试如下更改您的cmd脚本(请注意添加了“退出/ b 1”):

@echo off
setlocal

cmd /c dir aaa
IF %ERRORLEVEL% NEQ 0 GOTO fail
GOTO end
:fail
echo - Script failed
exit /b 1

:end
endlocal