537

I've been looking for a way to terminate a PowerShell (PS1) script when an unrecoverable error occurs within a function. For example:

function foo() {
    # Do stuff that causes an error
    $host.Exit()
}

Of course there's no such thing as $host.Exit(). There is $host.SetShouldExit(), but this actually closes the console window, which is not what I want. What I need is something equivalent to Python's sys.exit() that will simply stop execution of the current script without further ado.

Edit: Yeah, it's just exit.

GChuf
  • 1,135
  • 1
  • 17
  • 28
kprobst
  • 16,165
  • 5
  • 32
  • 53
  • 12
    If you want to avoid closing the PowerShell window or ISE in my case; use "return" instead. It just ends the current running context. "New guy" thoroughly explains all options for educational purposes; you might want to consider changing your accepted answer (currently has more up votes anyway) for future StackOverflow users. It will allow you to debug the script as well. – ZaxLofful Mar 24 '16 at 19:09
  • 1
    Does this answer your question? [What exactly is "exit" in PowerShell?](https://stackoverflow.com/questions/1275090/what-exactly-is-exit-in-powershell) – Mark Schultheiss Jan 17 '20 at 23:26

11 Answers11

778

I realize this is an old post but I find myself coming back to this thread a lot as it is one of the top search results when searching for this topic. However, I always leave more confused then when I came due to the conflicting information. Ultimately I always have to perform my own tests to figure it out. So this time I will post my findings.

TL;DR Most people will want to use Exit to terminate a running scripts. However, if your script is merely declaring functions to later be used in a shell, then you will want to use Return in the definitions of said functions.

Exit vs Return vs Break

  • Exit: This will "exit" the currently running context. If you call this command from a script it will exit the script. If you call this command from the shell it will exit the shell.

    If a function calls the Exit command it will exit what ever context it is running in. So if that function is only called from within a running script it will exit that script. However, if your script merely declares the function so that it can be used from the current shell and you run that function from the shell, it will exit the shell because the shell is the context in which the function contianing the Exit command is running.

    Note: By default if you right click on a script to run it in PowerShell, once the script is done running, PowerShell will close automatically. This has nothing to do with the Exit command or anything else in your script. It is just a default PowerShell behavior for scripts being ran using this specific method of running a script. The same is true for batch files and the Command Line window.

  • Return: This will return to the previous call point. If you call this command from a script (outside any functions) it will return to the shell. If you call this command from the shell it will return to the shell (which is the previous call point for a single command ran from the shell). If you call this command from a function it will return to where ever the function was called from.

    Execution of any commands after the call point that it is returned to will continue from that point. If a script is called from the shell and it contains the Return command outside any functions then when it returns to the shell there are no more commands to run thus making a Return used in this way essentially the same as Exit.

  • Break: This will break out of loops and switch cases. If you call this command while not in a loop or switch case it will break out of the script. If you call Break inside a loop that is nested inside a loop it will only break out of the loop it was called in.

    There is also an interesting feature of Break where you can prefix a loop with a label and then you can break out of that labeled loop even if the Break command is called within several nested groups within that labeled loop.

    While ($true) {
        # Code here will run
    
        :myLabel While ($true) {
            # Code here will run
    
            While ($true) {
                # Code here will run
    
                While ($true) {
                    # Code here will run
                    Break myLabel
                    # Code here will not run
                }
    
                # Code here will not run
            }
    
            # Code here will not run
        }
    
        # Code here will run
    }
    
New Guy
  • 8,606
  • 1
  • 15
  • 12
  • 62
    Also worth noting that `Exit` can take a return code as a parameter (defaults to 0) - e.g. `Exit 3`. – aucuparia Jul 10 '14 at 10:45
  • 3
    I agree, this is a much better answer. "Break" can have unintended consequences. – iagomartinez Oct 16 '14 at 17:59
  • I'm not sure your comment about "Exit" is completely correct although this is a great answer overall. Exit seems to be causing the ISE to close in a way that nothing else seems to be doing. Simply exiting the context (for instance, the script completing) does not do this. – Bill K Aug 12 '16 at 22:18
  • 3
    @BillK Indeed. I have updated the answer. When I first wrote this I remember not finding any official documentation on Exit. I then did a `Get-Command Exit` and `Get-Alias Exit` with no results. I then looked to see if it was a keyword and found no official documentation on it. Looking at it now however, I do not know how I came to that conclusion. Clearly it is a keyword (https://technet.microsoft.com/en-us/library/hh847744.aspx). Perhaps because Exit is one of the only keywords that doesn't have its own about_ help topic and therefore the list of topics in the left sidebar didn't include it. – New Guy Aug 14 '16 at 13:18
  • 15
    What about Throw? – JDC Oct 18 '16 at 10:12
  • But how to close the powershell windows (opened with a context menu launched by the registry)? – JinSnow May 23 '19 at 16:09
  • 1
    Is it applicable to return 0, 1, or 2, to indicate traditional error codes a la `exit`? – Josh Desmond May 28 '20 at 03:32
  • @iagomartinez What do you mean with "unintended consequences"? Everything can have "unintended consequences" if you don't know what you're doing. I think "break" does exactly what it should do. – The incredible Jan Aug 31 '23 at 07:25
472

You should use the exit keyword.

StackzOfZtuff
  • 2,534
  • 1
  • 28
  • 25
Michael Bray
  • 14,998
  • 7
  • 42
  • 68
  • 157
    How is this the accepted answer? It does specifically "closes the console window" which the asker said "which is not what I want." – claudekennilol Mar 13 '13 at 20:22
  • 5
    @claudekennilol Only the question asker can accept an answer. Either they missed the fact that exit is supposed to close the window, or they changed their mind and deemed that acceptable for their purpose. – Iszi Aug 13 '13 at 05:25
  • I overlooked a powershell console I didn't open, with the -NoExit switch, make sure this isn't there or ya it won't work, obvious but ya – Clarence Liu Feb 09 '14 at 06:47
  • 4
    It does not close the console window in v3 or v4, which I use. Well, it will if you run the script from explorer, but no matter how you end the script it will do that. If running from a PowerShell command window it does not close the window. – Joshua Nurczyk Jan 20 '15 at 07:05
  • 7
    Consider adding an error code if you're exiting due to abnormal circumstances. Like `Exit -1` or `Exit 1`. Any number other than `0` resolves `$?` to `False`. – ADTC Dec 10 '17 at 17:18
  • 1
    @claudekennilol It doesn't exit the console window when you run the script from a console. This behaves similarly to python's `sys.exit`, as was asked. `$host.SetShouldExit()` closes the console window when running a script from the console. What he didn't want. This seems to have the desired behavior to me... – iCodeSometime Sep 25 '18 at 13:19
  • I found out that when the server is out of memory, it can cause ps exit issues. – Robot70 Mar 09 '20 at 13:50
  • Note that ```return``` did not act as expected either, so ```Exit``` is recommended. – m1m1k Sep 22 '21 at 14:59
91

Exit will exit PowerShell too. If you wish to "break" out of just the current function or script - use Break :)

If ($Breakout -eq $true)
{
     Write-Host "Break Out!"
     Break
}
ElseIf ($Breakout -eq $false)
{
     Write-Host "No Breakout for you!"
}
Else
{
    Write-Host "Breakout wasn't defined..."
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
EverydayNerd
  • 943
  • 6
  • 2
  • 7
    Please don't use `break` when wanting to just break out of the current function... calling scripts can be disrupted as well! – DannyMeister Aug 18 '17 at 01:28
  • https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_break?view=powershell-7.3 "break out of just the current function" sounds weird. To leave a a function you use "return". – The incredible Jan Aug 31 '23 at 07:28
59

Write-Error is for non-terminating errors and throw is for terminating errors

The Write-Error cmdlet declares a non-terminating error. By default, errors are sent in the error stream to the host program to be displayed, along with output.

Non-terminating errors write an error to the error stream, but they do not stop command processing. If a non-terminating error is declared on one item in a collection of input items, the command continues to process the other items in the collection.

To declare a terminating error, use the Throw keyword. For more information, see about_Throw (http://go.microsoft.com/fwlink/?LinkID=145153).

Community
  • 1
  • 1
Greg Bray
  • 14,929
  • 12
  • 80
  • 104
  • 5
    This seems the most-correct way to terminate an activity with an error. It delegates to the caller to attempt to handle the error, which is much better than simply attempting to terminate abruptly. – Paul Turner Feb 10 '14 at 15:59
  • For me, at least in module functions, throw exits but doesn't set an exit code. This was executed via CLI e.g. `powershell -command "& module-function ..."`. I needed to convert those functions to throw to a wrapping try-catch and exit from that wrapping catch in order to actually output an error exit code. – Josh Mar 16 '16 at 14:37
  • 2
    Don't forget `$PSCmdlet.ThrowTerminatingError()` for those instances when throw just can't get the job done (known issue with none terminating errors from `throw`) – Djarid Apr 15 '16 at 13:08
37

Terminates this process and gives the underlying operating system the specified exit code.

https://msdn.microsoft.com/en-us/library/system.environment.exit%28v=vs.110%29.aspx

[Environment]::Exit(1)

This will allow you to exit with a specific exit code, that can be picked up from the caller.

gabriwinter
  • 546
  • 4
  • 5
  • 3
    In PowerShell, you can simply use the built-in Exit for this, e.g. `Exit 1`. – Jonas Apr 06 '17 at 10:14
  • 5
    built-in Exit won't always work as you expect. Try this in powershell: "Exit 5" > test1.ps1 powershell.exe .\test1.ps1 $lastexitcode "[Environment]::Exit(5)" > test2.ps1 powershell.exe .\test2.ps1 $lastexitcode – gabriwinter Dec 19 '17 at 16:26
  • 4
    `[Environment]::Exit(1)` has the side effect of exiting my powershell window when I invoke it in a script, where as using `exit` doesn't appear to do so. – Josh Desmond Mar 15 '20 at 16:34
32

Throwing an exception will be good especially if you want to clarify the error reason:

throw "Error Message"

This will generate a terminating error.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amr Bahaa
  • 1,057
  • 9
  • 9
  • 8
    I don't think this adds any more than Greg Bray's answer nearly a year earlier https://stackoverflow.com/a/20556550/695671 – Jason S Jan 30 '19 at 20:27
  • I used this for to, e.g.: Throw "The current value of my variable: $MyVariable", it was very helpful to me – George D Girton Aug 01 '21 at 22:41
  • 1
    Greg Bray did not include an example code, at least I don't see it as of now. – devildelta Dec 23 '22 at 07:34
  • @devildelta the provided code is so trivial, I'm not sure it really adds real value. (how does the caller handle this? How does this behave inside a script vs a function?) – PC Luddite Apr 07 '23 at 06:23
  • @PCLuddite You must understand that sometimes we need a practical runnable snippet to start with, instead of feeding lots of API doc that give zero syntax, especially for languages that are easily executable in environment to try and error. The value is that I can start working in the thing from zero to one, and then I can continue improving the thing from one to many by reading the API docs, if it is helpful. – devildelta Apr 22 '23 at 04:59
26

I think you are looking for Return instead of Break. Break is typically used for loops and only breaks from the innermost code block. Use Return to exit a function or script.

Rob
  • 3,418
  • 1
  • 19
  • 27
  • 10
    This is not correct--the OP specifically asks for exiting a script _from within a function_. `Return` will simply return from the function, not from the script. (`Return` at the _top_ level of a script will terminate the script, but that was not the question.) – Michael Sorens Jan 09 '14 at 18:29
  • 1
    was this 'answer' actually comments on EverydayNerd answer? – tkokasih Apr 10 '14 at 08:42
  • @tkokasih Perhaps it was intended as a comment but the way it came out, it's an excellently kick-ass answer.Not only does it address the actual question (making it an answer). It also provides additional relevants (hence excellency). And above all, it does it in two lines of text (definitely kickass'y, if yet understandably easy to mistake as a comment). Would you agree? – Konrad Viltersten Jan 04 '21 at 11:42
18

I coincidentally found out that Break <UnknownLabel> (e.g. simply Break Script, where the label Script doesn't exists) appears to break out of the entire script (even from within a function) and keeps the host alive.
This way you could create a function that breaks the script from anywhere (e.g. a recursive loop) without knowing the current scope (and creating labels):

Function Quit($Text) {
    Write-Host "Quiting because: " $Text
    Break Script
} 
iRon
  • 20,463
  • 10
  • 53
  • 79
  • 1
    Your answer is true, but be aware this can cause problems for callers of your script if they disagree with your desire to exit the entire script: https://stackoverflow.com/questions/45746588/powershell-try-catch-does-not-catch-a-break-statement – DannyMeister Aug 18 '17 at 01:31
14

May be it is better to use "trap". A PowerShell trap specifies a codeblock to run when a terminating or error occurs. Type

Get-Help about_trap

to learn more about the trap statement.

fpschultze
  • 153
  • 6
6

I thought up a neat little trick to do just that, when I wanted a function to exit a script without throwing an error, but not exit the console if the function was used from there. It involves the $MyInvocation automatic variable's CommandOrigin property.

if ( $MyInvocation.CommandOrigin -eq 'Internal' ) { exit }

If the function is ran from the console, the CommandOrigin will be Runspace.

Vopel
  • 662
  • 6
  • 11
5

I used this for a reruning of a program. I don't know if it would help, but it is a simple if statement requiring only two different entry's. It worked in powershell for me.

$rerun = Read-Host "Rerun report (y/n)?"

if($rerun -eq "y") { Show-MemoryReport }
if($rerun -eq "n") { Exit }

Don't know if this helps, but i believe this would be along the lines of terminating a program after you have run it. However in this case, every defined input requires a listed and categorized output. You could also have the exit call up a new prompt line and terminate the program that way.

Michael Meli
  • 81
  • 1
  • 7