Beenden eines Skripts in PowerShell

394

Ich habe nach einer Möglichkeit gesucht, ein PowerShell (PS1) -Skript zu beenden, wenn innerhalb einer Funktion ein nicht behebbarer Fehler auftritt. Zum Beispiel:

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

Natürlich gibt es so etwas nicht $host.Exit(). Es gibt $host.SetShouldExit(), aber dies schließt tatsächlich das Konsolenfenster, was nicht das ist, was ich will. Was ich brauche, ist etwas Äquivalentes zu Pythons sys.exit(), das einfach die Ausführung des aktuellen Skripts ohne weiteres beendet.

Edit: Ja, es ist nur so exit. Duh.

kprobst
quelle
8
Wenn Sie in meinem Fall das Schließen des PowerShell-Fensters oder der ISE vermeiden möchten; Verwenden Sie stattdessen "return". Es beendet nur den aktuell laufenden Kontext. "Neuer Typ" erklärt gründlich alle Optionen für Bildungszwecke; Möglicherweise möchten Sie Ihre akzeptierte Antwort (die derzeit ohnehin mehr Stimmen enthält) für zukünftige StackOverflow-Benutzer ändern. Damit können Sie auch das Skript debuggen.
ZaxLofful
Beantwortet das deine Frage? Was genau ist "Beenden" in PowerShell?
Mark Schultheiss

Antworten:

389

Sie sollten das exitSchlüsselwort verwenden .

Michael Bray
quelle
15
Heiliger Mist, wenn ich nicht so sehr versucht hätte herauszufinden, wie man diese Dinge klug macht, hätte ich das wahrscheinlich zuerst versucht und herausgefunden, dass es funktioniert :) Danke.
kprobst
118
Wie ist das die akzeptierte Antwort? Es schließt speziell "das Konsolenfenster", was der Fragesteller sagte "was nicht das ist, was ich will".
Cladekennilol
3
@claudekennilol Nur der Fragesteller kann eine Antwort akzeptieren. Entweder haben sie die Tatsache übersehen, dass der Ausgang das Fenster schließen soll, oder sie haben ihre Meinung geändert und dies für ihren Zweck als akzeptabel erachtet.
Iszi
3
Das von mir verwendete Konsolenfenster in Version 3 oder Version 4 wird nicht geschlossen. Nun, es wird, wenn Sie das Skript vom Explorer ausführen, aber egal wie Sie das Skript beenden, wird es das tun. Wenn Sie in einem PowerShell-Befehlsfenster ausgeführt werden, wird das Fenster nicht geschlossen.
Joshua Nurczyk
14
Die Antwort von New Guy ist viel gründlicher und die Verdiener werden als akzeptiert markiert.
Jim Aho
585

Mir ist klar, dass dies ein alter Beitrag ist, aber ich komme häufig auf diesen Thread zurück, da er eines der besten Suchergebnisse bei der Suche nach diesem Thema ist. Ich bin jedoch immer verwirrter, als wenn ich aufgrund der widersprüchlichen Informationen gekommen bin. Letztendlich muss ich immer meine eigenen Tests durchführen, um es herauszufinden. Also werde ich diesmal meine Ergebnisse veröffentlichen.

TL; DR Die meisten Benutzer möchten Exitein laufendes Skript beenden. Wenn Ihr Skript jedoch lediglich Funktionen deklariert, die später in einer Shell verwendet werden sollen, sollten Sie diese Returnin den Definitionen dieser Funktionen verwenden.

Exit vs Return vs Break

  • Beenden: Dadurch wird der aktuell ausgeführte Kontext "beendet". Wenn Sie diesen Befehl über ein Skript aufrufen, wird das Skript beendet. Wenn Sie diesen Befehl über die Shell aufrufen, wird die Shell beendet.

    Wenn eine Funktion den Befehl Beenden aufruft, wird der Kontext beendet, in dem sie ausgeführt wird. Wenn diese Funktion also nur innerhalb eines laufenden Skripts aufgerufen wird, wird das Skript beendet. Wenn Ihr Skript die Funktion jedoch nur deklariert, damit sie von der aktuellen Shell aus verwendet werden kann, und Sie diese Funktion von der Shell aus ausführen, wird die Shell beendet, da die Shell der Kontext ist, in dem die Funktion ausgeführt wird, die den ExitBefehl enthält.

    Hinweis: Wenn Sie mit der rechten Maustaste auf ein Skript klicken, um es in PowerShell auszuführen, wird PowerShell standardmäßig automatisch geschlossen, sobald das Skript ausgeführt wurde. Dies hat nichts mit dem ExitBefehl oder etwas anderem in Ihrem Skript zu tun . Dies ist nur ein Standardverhalten von PowerShell für Skripts, die mit dieser speziellen Methode zum Ausführen eines Skripts ausgeführt werden. Gleiches gilt für Batchdateien und das Befehlszeilenfenster.

  • Zurück: Hiermit kehren Sie zum vorherigen Anrufpunkt zurück. Wenn Sie diesen Befehl über ein Skript (außerhalb von Funktionen) aufrufen, kehrt er zur Shell zurück. Wenn Sie diesen Befehl von der Shell aus aufrufen, kehrt er zur Shell zurück (dies ist der vorherige Aufrufpunkt für einen einzelnen Befehl, der von der Shell ausgeführt wird). Wenn Sie diesen Befehl von einer Funktion aus aufrufen, kehrt er dorthin zurück, von wo aus die Funktion aufgerufen wurde.

    Die Ausführung von Befehlen nach dem Aufrufpunkt, an den sie zurückgegeben werden, wird ab diesem Punkt fortgesetzt. Wenn ein Skript von der Shell aufgerufen wird und den ReturnBefehl außerhalb von Funktionen enthält, müssen bei der Rückkehr zur Shell keine Befehle mehr ausgeführt werden, sodass ein Returnauf diese Weise verwendetes Skript im Wesentlichen dasselbe ist wie Exit.

  • Pause: Dies wird aus Schleifen ausbrechen und Fälle wechseln. Wenn Sie diesen Befehl aufrufen, während Sie sich nicht in einer Schleife oder einem Schalter befinden, wird er aus dem Skript ausbrechen. Wenn Sie Breakin einer Schleife aufrufen, die in einer Schleife verschachtelt ist, bricht diese nur aus der Schleife aus, in der sie aufgerufen wurde.

    Es gibt auch eine interessante Funktion, Breakbei der Sie einer Schleife eine Bezeichnung voranstellen und dann aus dieser beschrifteten Schleife ausbrechen können, selbst wenn der BreakBefehl innerhalb mehrerer verschachtelter Gruppen innerhalb dieser beschrifteten Schleife aufgerufen wird.

    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
    }
Neuer Typ
quelle
39
Erwähnenswert ist auch, dass Exitein Rückkehrcode als Parameter verwendet werden kann (standardmäßig 0) - z Exit 3.
Aucuparia
2
Ich stimme zu, das ist eine viel bessere Antwort. "Pause" kann unbeabsichtigte Folgen haben.
Iagomartinez
Ich bin mir nicht sicher, ob Ihr Kommentar zu "Beenden" vollständig korrekt ist, obwohl dies insgesamt eine großartige Antwort ist. Der Ausgang scheint dazu zu führen, dass die ISE auf eine Weise geschlossen wird, die sonst nichts zu tun scheint. Das einfache Verlassen des Kontexts (z. B. das Ausfüllen des Skripts) reicht nicht aus.
Bill K
1
@ BillK In der Tat. Ich habe die Antwort aktualisiert. Als ich das zum ersten Mal schrieb, erinnere ich mich, dass ich bei Exit keine offizielle Dokumentation gefunden habe. Ich habe dann ein Get-Command Exitund Get-Alias Exitohne Ergebnisse gemacht. Ich habe dann nachgesehen, ob es sich um ein Schlüsselwort handelt, und keine offizielle Dokumentation dazu gefunden. Wenn ich es jetzt betrachte, weiß ich nicht, wie ich zu diesem Schluss gekommen bin. Dies ist eindeutig ein Schlüsselwort ( technet.microsoft.com/en-us/library/hh847744.aspx ). Vielleicht, weil Exit eines der wenigen Schlüsselwörter ist, das kein eigenes about_ help-Thema hat und daher in der Liste der Themen in der linken Seitenleiste nicht enthalten ist.
New Guy
6
Was ist mit Werfen?
JDC
80

Exitbeendet auch PowerShell. Wenn Sie nur aus der aktuellen Funktion oder dem aktuellen Skript "ausbrechen" möchten, verwenden Sie 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..."
}
EverydayNerd
quelle
5
Bitte nicht verwenden, breakwenn Sie nur aus der aktuellen Funktion ausbrechen möchten ... das Aufrufen von Skripten kann ebenfalls unterbrochen werden!
DannyMeister
49

Write-Error ist für nicht terminierende Fehler und throw für terminierende Fehler

Das Cmdlet Write-Error deklariert einen nicht terminierenden Fehler. Standardmäßig werden Fehler im Fehlerstrom zusammen mit der Ausgabe an das anzuzeigende Hostprogramm gesendet.

Nicht terminierende Fehler schreiben einen Fehler in den Fehlerstrom, stoppen jedoch nicht die Befehlsverarbeitung. Wenn für ein Element in einer Sammlung von Eingabeelementen ein nicht beendender Fehler deklariert wird, verarbeitet der Befehl die anderen Elemente in der Sammlung weiter.

Verwenden Sie das Schlüsselwort Throw, um einen Beendigungsfehler zu deklarieren. Weitere Informationen finden Sie unter about_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).

Greg Bray
quelle
4
Dies scheint der korrekteste Weg zu sein, um eine Aktivität mit einem Fehler zu beenden. Es delegiert an den Anrufer, um zu versuchen, den Fehler zu behandeln. Dies ist viel besser als der Versuch, ihn abrupt zu beenden.
Paul Turner
Für mich, zumindest in Modulfunktionen, werfen Sie Exits, setzen aber keinen Exit-Code. Dies wurde über CLI zB ausgeführt powershell -command "& module-function ...". Ich musste diese Funktionen konvertieren, um sie in einen Wrapping-Try-Catch zu werfen und diesen Wrapping-Catch zu verlassen, um tatsächlich einen Fehler-Exit-Code auszugeben.
Josh
2
Vergessen Sie nicht $PSCmdlet.ThrowTerminatingError()für jene Fälle, in denen der Wurf den Job einfach nicht erledigen kann (bekanntes Problem, bei dem keine Fehler beim Beenden von auftreten throw)
Djarid
33

Beendet diesen Prozess und gibt dem zugrunde liegenden Betriebssystem den angegebenen Exit-Code.

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

[Environment]::Exit(1)

Auf diese Weise können Sie mit einem bestimmten Beendigungscode beenden, der vom Anrufer abgeholt werden kann.

gabriwinter
quelle
3
In PowerShell können Sie dazu einfach den integrierten Exit verwenden, z Exit 1.
Jonas
3
Der integrierte Exit funktioniert nicht immer wie erwartet. Versuchen Sie dies in Powershell: "Exit 5"> test1.ps1 Powershell.exe. \ Test1.ps1 $ lastexitcode "[Umgebung] :: Exit (5)"> test2.ps1 Powershell.exe. \ Test2.ps1 $ lastexitcode
gabriwinter
1
[Environment]::Exit(1)hat den Nebeneffekt, dass ich mein Powershell-Fenster verlasse, wenn ich es in einem Skript aufrufe, wo exitdies anscheinend nicht der Fall ist.
Josh Desmond
25

Ich denke du suchst Returnstatt Break. Break wird normalerweise für Schleifen verwendet und nur vom innersten Codeblock. Verwenden Sie die Eingabetaste, um eine Funktion oder ein Skript zu beenden.

rauben
quelle
7
Dies ist nicht korrekt - das OP fordert ausdrücklich an, ein Skript innerhalb einer Funktion zu beenden . Returnwird einfach von der Funktion zurückkehren, nicht vom Skript. ( ReturnAuf der obersten Ebene eines Skripts wird das Skript beendet, aber das war nicht die Frage.)
Michael Sorens
1
War diese 'Antwort' tatsächlich ein Kommentar zur EverydayNerd-Antwort?
Tkokasih
22

Das Auslösen einer Ausnahme ist besonders dann gut, wenn Sie den Fehlergrund klären möchten:

throw "Error Message"

Dies erzeugt einen Beendigungsfehler.

Amr Bahaa
quelle
3
Ich glaube nicht, dass dies mehr als Greg Brays Antwort fast ein Jahr zuvor hinzufügt stackoverflow.com/a/20556550/695671
Jason S
12

Vielleicht ist es besser, "Falle" zu verwenden. Ein PowerShell-Trap gibt einen Codeblock an, der ausgeführt werden soll, wenn ein Abschluss oder ein Fehler auftritt. Art

Get-Help about_trap

um mehr über die Trap-Anweisung zu erfahren.

fpschultze
quelle
10

Ich habe zufällig herausgefunden, dass (z. B. einfach , wo das Label nicht existiert ) aus dem gesamten Skript auszubrechen scheint (sogar innerhalb einer Funktion) und den Host am Leben hält. Auf diese Weise können Sie eine Funktion erstellen, die das Skript von einer beliebigen Stelle aus unterbricht (z. B. eine rekursive Schleife), ohne den aktuellen Bereich zu kennen (und Beschriftungen zu erstellen):Break <UnknownLabel>Break ScriptScript

Function Quit($Text) {
    Write-Host "Quiting because: " $Text
    Break Script
} 
Eisen
quelle
1
Ihre Antwort ist wahr, aber beachten Sie, dass dies für Anrufer Ihres Skripts Probleme verursachen kann, wenn sie nicht mit Ihrem Wunsch übereinstimmen,
DannyMeister
5

Ich habe dies für eine Wiederholung eines Programms verwendet. Ich weiß nicht, ob es helfen würde, aber es ist eine einfache if-Anweisung, die nur zwei verschiedene Einträge erfordert. Es hat in Powershell für mich funktioniert.

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

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

Ich weiß nicht, ob dies hilft, aber ich glaube, dies würde dazu führen, dass ein Programm beendet wird, nachdem Sie es ausgeführt haben. In diesem Fall erfordert jedoch jede definierte Eingabe eine aufgelistete und kategorisierte Ausgabe. Sie können den Exit auch eine neue Eingabeaufforderungszeile aufrufen lassen und das Programm auf diese Weise beenden.

Michael Meli
quelle