2

I noticed a strange behaviour in Powershell. There are two .ps1 files:

main.ps1:

echo "running exit.ps1"
$myexitcode = & ".\exit.ps1" "hello" | select -Last 1 
echo "Return code is $myexitcode"
echo "Exit code is $?"
echo "after running exit.ps1"

exit.ps1:

echo "processing args " $args
$script:_serverExitStatus = 9

#this is causing the program to exit completely
[System.Environment]::exit(3)

#BUT this is NOT causing the program to exit completely
#[System.Environment]::exit

With the above code, the process is getting completely exited and the output doesn't contain "after running exit.ps1". However, if I comment [System.Environment]::exit(3) and uncomment [System.Environment]::exit, output contains "after running exit.ps1"

I feel that exit must always exit completely. But, that's not the case with [System.Environment]::exit

What is the difference between these two things and which one is correct?

Version:

$PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      22000  832

Thank you.

1
  • 2
    [System.Environment]::Exit is a method, you need to invoke it for it to do anything :) Commented Sep 2, 2022 at 14:56

2 Answers 2

5

To elaborate on Abdul Niyas P M's helpful answer:

In PowerShell, referencing a .NET method without () doesn't actually invoke the method, it prints its signatures (overload definitions), i.e. it performs reflection to show you what arguments you'd have to pass in an actual invocation:

PS> [System.Environment]::Exit

OverloadDefinitions
-------------------
static void Exit(int exitCode)

As you can see, the method takes an unconditional int-typed argument specifying the exit code to report, which implies that you must pass a value on invocation; if you want to signal success, simply use [System.Environment]::Exit(0)

However, I wonder if this method is really the right tool for your task, and whether use of PowerShell's exit statement is what you're looking for - see below.


  • Use PowerShell's exit statement to exit the running script.

    • Without an argument, 0 is reported as the exit code; pass a number to set the exit code explicitly (e.g. exit 3).

    • Inside a PowerShell session, this exit code is reported in the automatic $LASTEXITCODE variable, not in the automatic $? variable - the latter is an abstract success indicator in the form of a Boolean value ($true or $false), and it effectively translates a $LASTEXITCODE value of 0 to $true, and any nonzero value to $false.

    • When a script is invoked via PowerShell's CLI (powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+):

      • With the -File parameter, the exit code also becomes the PowerShell process' exit code
      • With the (potentially implied) -Command parameter, it is the value of $? after the last statement executes that is translated to an exit code, with $true becoming 0, and $false becoming 1; thus, if the script invocation is the last statement, any nonzero exit code is effectively reported as 1; preserving the specific exit code therefore requires appending ; exit $LASTEXITCODE to the command string.
  • Use the [System.Environment]::exit($number) .NET method to instantly exit (terminate) the current process and thereby the whole PowerShell session.

    • Therefore, it's best to avoid this method, unless you truly need to unconditionally terminate the entire process.
Sign up to request clarification or add additional context in comments.

4 Comments

The documentation is missing the fact, that $LASTEXITCODE reports the exit code of scripts as well, not just "native programs".
Done: github.com/MicrosoftDocs/PowerShell-Docs/issues/9194. Let me know if you have suggestions to improve the proposed new wording. As you propably know, I'm not native english speaker. ;-)
@zett42 Maybe the current docs are already sufficient, because a script is no executable itself. It has to be run by powershell.exe or pwsh.exe (aka native programs) which will exit with an exit code (maybe through instructions of the script).
@stackprotector No, it isn't. Scripts returning with the exit statement set the $LASTEXITCODE variable, even if directly called from another script like .\scriptname.ps1, so a call to powershell.exe or pwsh.exe is not involved. See demo at the github docs issue.
3

[System.Environment]::exit is a static method and requires () and exitCode parameter to do the actual work. So [System.Environment]::exit(3) is the actual code that terminates the process with status code(3)

2 Comments

Thanks for the answer. So, [System.Environment]::exit doesn't terminate the process?
@Austin Yes that's correct!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.