PowerShell CLI: exits with exit code 1 rather than the specific $LASTEXITCODE of the last statement
See original GitHub issueFollow-up from #11461.
When using the PowerShell CLI with -c / -Command, PowerShell by design sets its exit code based on the success status of the last statement executed in the specified command string.
If the last statement is a PowerShell command, success can only be derived from the automatic success-status variable, $?. As a Boolean, the only sensibly way to map that to an exit code is to map $true to 0, and $false to 1 - this works as expected.
However, if the last statement is a call to an external program, a process exit code is directly available from the child process in which the external program executed, as reflected in automatic variable $LASTEXITCODE. The same potentially applies to a call to an (in-process) call to a *.ps1 script that uses exit <n>.
Given that $LASTEXITCODE can contain more specific information than just abstract success vs. failure, it makes sense to preserve this specific information in the caller’s $LASTEXITCODE value instead of mapping it in a lossy manner to either 0 ($LASTEXITCODE being 0) or 1 (any nonzero $LASTEXITCODE value) - which is what currently happens.
While this would technically be a breaking change, it seems to me that it falls into Bucket 3: Unlikely Grey Area:
-
In the typical case, code checks for abstract success vs. failure of child processes, which means that any nonzero exit code indicates failure, without regard to the specific nonzero value.
-
The proposed change wouldn’t interfere with that, while at the same time providing more specific information to code that does care about the specific nonzero exit code reported.
Steps to reproduce
On Unix:
& { pwsh -noprofile -c 'sh -c ''exit 5'''; $LASTEXITCODE } | Should -Be 5
Expected behavior
The test should pass.
Actual behavior
The test fails, because the process exit code 5 was unexpectedly mapped to 1 in the caller’s scope:
Expected 5, but got 1.
Environment data
PowerShell Core 7.1.0-preview.6
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:12 (6 by maintainers)

Top Related StackOverflow Question
Unfortunately, it’s not documented, though, so let’s start there:
about_Pwsh: https://github.com/MicrosoftDocs/PowerShell-Docs/issues/6548about_Scripts: https://github.com/MicrosoftDocs/PowerShell-Docs/issues/6559In the process I discovered:
<kbd>Ctrl-C</kbd> with
-Filesets the exit code to0(!) - see #13523Somewhat ironically, in-session termination of a script with <kbd>Ctrl-C</kbd> sets
$LASTEXITCODEto the POSIX-compliant130, but only on Unix; on Windows,$LASTEXITCODEisn’t set at all in that case (same as not exiting withexitfrom the script - see #11712)A non-numeric
exitargument or a numeric value outside the platform-supported range ([int]on Windows,[byte]on Unix) quietly results in0(!).@Northman-de
It is PowerShell’s job - as a shell - to play as nicely with the outside world as it can - an aspiration that it has historically often fallen short of.
With
-c/-Command, PowerShell’s CLI sets an exit code deliberately - which is good - but it throws away information in the process - which is bad.Clearly, the design intent was to translate the success status of the (last) command executed in the command string into an appropriate process exit code; for PowerShell-native commands mapping
$?to0and1is the best that can be done, but for external executables and*.ps1scripts an appropriate exit code is directly available and should be used as such.Note that calling a
*.ps1script with-Filedoes respect anexit <n>statement and reports<n>as the exit code:There are situations where you need to call
.ps1scripts via-c/-Commandinstead, such as when you need to pass array arguments.Does this discrepancy make sense to you? I think it amounts to a pitfall that is easily avoided.
This is really a separate issue, worth tackling in its own right. It is an issue that (a) already exists and (b) one that, if anything, could be helped by resolving the issue at hand, making workarounds easier.
It is unfortunate that PowerShell chose to use the nondescript exit code
1for termination via <kbd>Ctrl-C</kbd> and for unhandled script-terminating errors (created withthrow, for instance).POSIX-like shells more sensibly reserve a range of exit codes to indicate termination by signal (which <kbd>Ctrl-C</kbd> constitutes, via
SIGINT):128 + <signal-number; thus, sinceSIGINThas a numeric value of2, exit code130is reported.