Exit code from a batch file is not propagated to the parent powershell script

荒凉一梦 提交于 2021-02-19 08:25:07

问题


Please, observe:

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

Now if I run it in the command prompt:

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>

Now I am running it from 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>

From what I know the exit code is supposed to propagate correctly. So, what is the problem?


回答1:


First: ERRORLEVEL is not %ERRORLEVEL%.

Second, the errorlevel is not the same as a process exit code.

Try altering your cmd script as follows (note the addition of "exit /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



回答2:


Note: This answer was substantially rewritten after new information came to light.

To complement jazzdelightsme's effective solution with some general guidance and background information:

  • When calling a batch file from outside cmd.exe, such as from PowerShell, invoke it as cmd /c call file.cmd to ensure that it behaves as it would when called from inside cmd.exe with respect to its exit code (error level), i.e. to ensure that the batch file's exit code also becomes cmd.exe's process exit code.

  • Without using call, you'll only get the desired behavior if you ensure that all code paths exit in one of the following ways - and missing a code path is an easy mistake to make:

    • exit with no arguments, which correctly relays the most recently executed command's exit code.

      • Caveat: exit without /b instantly exits the cmd.exe instance as a whole, so it isn't suitable for batch files that may be run interactively or must be callable from other batch files and return control to those batch files.
    • exit /b <code> or exit <code>, where <code> represents the desired exit code, i.e. specifying an explicit exit code, as in jazzdelightsme's solution.

      • Caveat: exit /b without an explicit <code> argument does not pass the most recently executed command's exit code through without call - see this answer.

Additional background information, in the context of your code:

Bizarrely, with an outside invocation of a batch file without call, statements such as if, goto, echo, and endlocal, and even REM (but, curiously, not ::) reset the exit code that cmd.exe later reports to 0 - even though inside that cmd.exe session %ERRORLEVEL% is set as it usually is, meaning that such statements have no impact on the current %ERRORLEVEL% value.

Therefore:

  • When your batch file is run from inside cmd.exe, the specific statements that follow the command that sets %ERRORLEVEL% to 1 (cmd /c dir aaa), i.e. the if, goto, echo and endlocal statements, preserve this value, and %ERRORLEVEL% ends up with value 1 after exiting the batch file.

  • When your batch file is run from outside cmd.exe, and isn't invoked with cmd /c call, the same statements that follow the %ERRORLEVEL%-setting command suddenly reset the exit code that cmd.exe itself later reports to 0, instead of preserving the post-batch-file-execution %ERRORLEVEL% value.



来源:https://stackoverflow.com/questions/55289348/exit-code-from-a-batch-file-is-not-propagated-to-the-parent-powershell-script

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!