tl;dr
Rather than having to modify your batch file by adding an exit /b %ERRORLEVEL%
statement, you can modify the batch file's invocation by appending & exit
in order to achieve the same effect:
cmd.exe /c "$($ROOT_DIR)\batch.bat $REQUIRED_PARAMETERS $OPTIONAL_PARAMETERS & exit" |
Out-File -FilePath "$COMPARE_DIR\$LOG_FILENAME.log" -Append
This obscure solution is necessitated by the unfortunate fact that cmd.exe
doesn't reliably relay a batch file's exit code as its process exit code when the batch file is called from the outside, neither when a batch file is called directly nor via cmd.exe /c
- see this answer for details.
Note:
The ie
function that comes with the Native
module (Install-Module Native
) automatically applies this workaround, so that invocation as
ie "$($ROOT_DIR)\batch.bat" ...
would work as-is with respect to setting $LASTEXITCODE
(though you'd have to pass the arguments individually or via array variables, as discussed).
GitHub proposal #15143 advocates building this workaround into PowerShell itself, as part of a larger proposal to improve argument-passing to external programs on Windows, but the proposal was rejected.
As for what you tried:
This doesn't pass the arguments to the batch file:
& $BATCH_PATH $REQUIRED_PARAMETERS $OPTIONAL_PARAMETERS`
This syntax works in principle, but not if your variables contain multiple arguments as a single string. E.g., $REQUIRED_PARAMETERS = 'foo bar'
would not work, but specifying the arguments a an an array of strings would, $REQUIRED_PARAMETERS = 'foo', 'bar'
: In the former case, 'foo bar'
is passed as a single argument, in the latter case, the array elements become individual arguments.
This works, but LASTEXITCODE is always "0":
Start-Process -FilePath "C:\Windows\System32\cmd.exe" -ArgumentList "/c", "$BATCH_PATH", "$REQUIRED_PARAMETERS", "$OPTIONAL_PARAMETERS" -WindowStyle Hidden -PassThru -Wait -RedirectStandardOutput "$COMPARE_DIR\$(Get-Random).log"
I also tried to get the ExitCode-Property of the Process-Object, but it is also 0.
The automatic $LASTEXITCODE
variable is only set for direct calls to external programs, not when you use Start-Process
- which is generally the wrong tool for invoking console applications.
(As your statement implies, it is possible to get a process' exit code when Start-Process
is used, namely by adding -Wait -PassThru
to the call in order to wait for the process to exit and to return a System.Diagnostics.Process
instance whose exit code can then be inspected.
In the case at hand this wouldn't make a difference anyway, because the problem lies with cmd.exe
itself, not with how it is invoked.)