0

UPDATE: Solved, see comment

I'm trying to run a batch file inside a powershell script, where I need to pass two arguments and read the return code.

I tried and read $LASTEXITCODE, but it always returns me "0".

This doesn't pass the arguments to the batch file:

& $BATCH_PATH $REQUIRED_PARAMETERS $OPTIONAL_PARAMETERS | Out-File -FilePath "$COMPARE_DIR\$LOG_FILENAME.log" -Append

This works, but LASTEXITCODE is always "0":

cmd.exe /c "$($ROOT_DIR)\batch.bat $REQUIRED_PARAMETERS $OPTIONAL_PARAMETERS" | Out-File -FilePath "$COMPARE_DIR\$LOG_FILENAME.log" -Append

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.

2
  • 1
    I solved the issue after adding "exit /b %ERRORLEVEL%" to my batch file Commented May 7, 2021 at 18:05
  • 4
    Then create an answer or delete your question. Commented May 7, 2021 at 18:21

1 Answer 1

2

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.)

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.