1

Assume I have two files, script.ps1 and filename.cmd, and I run .\script.ps1 from a Powershell prompt:

script.ps1

Write-Host "About to run filename.cmd"
$proc = Start-Process -FilePath filename.cmd -NoNewWindow -Wait
Write-Host "proc: [$proc]"
Write-Host "LASTEXITCODE: [$LASTEXITCODE]

filename.cmd

@echo off
ECHO File returns ErrorLevel=1
exit /b 1

Output:

About to run filename.cmd
proc: []
LASTEXITCODE: []

Both proc and LASTEXITCODE are $null. My understanding was that somehow I could access the ErrorCode?

How do I read the failed error level (in this case 1) in my Powershell script?

satoukum
  • 1,188
  • 1
  • 21
  • 31

1 Answers1

1

To synchronously execute console applications, including batch files, call them directly, do not use Start-Process - see this answer.

Therefore:

Write-Host "About to run filename.cmd"
# For security reasons, PowerShell requires that you explicitly
# signal the intent to run an executable located *in the current directory*,
# hence the need for `./` (or `.\`)
# Only direct invocation of external programs (batch files) sets
# the automatic $LASTEXITCODE variable.
./filename.cmd
Write-Host "LASTEXITCODE: [$LASTEXITCODE]

As for what you tried:

Start-Process outputs nothing by default - except if you pass the -PassThru switch, in which case a System.Diagnostics.Process instance representing the newly started process is returned.

Assuming you've also specified -Wait, as in your case, you can then access the returned object's .ExitCode property to determine the exit code immediately afterwards.

Note that automatic variable $LASTEXITCODE is only set after direct invocation of external programs, as shown above.

Therefore, if you were to use Start-Process - which is not necessary in this case, as explained above - you'd have to use the following:

Write-Host "About to run filename.cmd"
$proc = Start-Process -PassThru -FilePath filename.cmd -NoNewWindow -Wait
Write-Host "proc: [$proc]"
Write-Host "exit coe: [$($proc.ExitCode)]
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Thanks this is very helpful. I ended up using ```Invoke-Expression -Command "filename.cmd" | Out-Host``` so that I could mock the call in my Pester tests, which appears to have worked like a charm using ```$LASTEXITCODE``` – satoukum Mar 27 '20 at 17:50
  • 1
    Glad to hear it, @satoukum. As a matter of habit, I suggest [avoiding `Invoke-Expression`](https://blogs.msdn.microsoft.com/powershell/2011/06/03/invoke-expression-considered-harmful/), so perhaps `Invoke-Command { ./filename.cmd }` is the better alternative. – mklement0 Mar 27 '20 at 17:59