HOWTO · PowerShell
Wie man ein Skript in Windows PowerShell beendet
Erfahren Sie, wann exit, return, throw, break, continue oder Stop-Process den richtigen Bereich beendet und einen verlässlichen PowerShell-Exitcode liefert.
Auf dieser Seite
Ein PowerShell-Skript zu beenden ist nicht immer derselbe Vorgang. Die richtige Anweisung hängt davon ab, ob der gesamte Skriptprozess, nur eine Funktion, eine Schleifeniteration oder ein anderer Betriebssystemprozess gestoppt werden soll.
| Ziel | Anweisung |
|---|---|
| Das Hauptskript beenden und einen Status melden | exit <Code> |
| Eine Funktion, ein Skript oder einen Skriptblock verlassen | return |
| Einen abfangbaren Fehler melden | throw |
Eine Schleife oder switch verlassen |
break |
Mit dem nächsten Schleifen- oder switch-Element fortfahren |
continue |
| Einen anderen lokalen Prozess beenden | Stop-Process |
Ein PowerShell-Skript mit exit beenden
exit beendet ein Skript oder eine PowerShell-Instanz. Eine optionale Ganzzahl wird zum Prozess-Exitcode: Üblicherweise steht 0 für Erfolg und ein Wert ungleich null für einen Fehler. Dokumentieren Sie die Bedeutung jedes Fehlercodes, damit Aufgabenplanung, CI und aufrufende Programme zuverlässig reagieren können.
Speichern Sie dieses Einstiegsskript als Check-Config.ps1:
param([Parameter(Mandatory)][string]$Path)
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
Write-Error "Configuration file not found: $Path"
exit 2
}
Write-Output 'Configuration file found.'
exit 0
Starten Sie es aus einer anderen PowerShell-Sitzung als Kindprozess und lesen Sie anschließend den Status:
powershell.exe -NoProfile -File .\Check-Config.ps1 -Path .\missing.json
$LASTEXITCODE
Der letzte Befehl gibt 2 aus. Verwenden Sie unter PowerShell 7 pwsh statt powershell.exe. PowerShell stellt den Status des Kindprozesses über $LASTEXITCODE bereit; in cmd.exe steht er in %ERRORLEVEL%.
Setzen Sie exit nur an der Grenze des Hauptskripts ein. Ruft eine wiederverwendbare Funktion exit auf, kann sie eine interaktive Sitzung, einen Test-Runner oder einen anderen Host schließen. Funktionen sollten daher Daten zurückgeben oder Fehler auslösen; erst das Einstiegsskript übersetzt das Ergebnis in einen Exitcode.
Den aktuellen Bereich mit return verlassen
return verlässt die aktuelle Funktion, das aktuelle Skript oder den aktuellen Skriptblock. Die Anweisung setzt nicht automatisch einen Prozess-Exitcode.
function Get-ConfigText {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
return $null
}
Get-Content -LiteralPath $Path -Raw
}
In einer normalen PowerShell-Funktion wird jeder nicht abgefangene Wert des Erfolgsstreams zur Ausgabe, nicht nur der Ausdruck hinter return. Schreiben Sie Diagnosemeldungen mit Write-Verbose oder in einen anderen passenden Stream, statt zusätzliche Zeichenfolgen mit Write-Output auszugeben.
Mit throw einen abfangbaren Fehler auslösen
throw erzeugt standardmäßig einen skriptbeendenden Fehler und durchläuft den Aufrufstack rückwärts, bis ein catch-Block oder trap ihn behandelt. Verwenden Sie throw, wenn eine Funktion kein gültiges Ergebnis liefern kann und der Aufrufer über die Behandlung entscheiden soll.
function Get-RequiredConfig {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
throw "Configuration file not found: $Path"
}
Get-Content -LiteralPath $Path -Raw
}
try {
$config = Get-RequiredConfig -Path '.\settings.json'
}
catch {
Write-Error $_
exit 2
}
Dieses Muster trennt zwei Aufgaben: Die Funktion beschreibt den Fehler mit throw, das Einstiegsskript fängt ihn ab und wählt den öffentlichen Exitcode. Nicht jeder Cmdlet-Fehler erreicht automatisch catch; verwenden Sie bei nicht beendenden Fehlern -ErrorAction Stop, wenn sie dort behandelt werden müssen.
break und continue nur in Kontrollblöcken verwenden
break verlässt die nächste umgebende Schleife oder switch-Anweisung. continue überspringt den Rest der aktuellen Iteration und beginnt die nächste.
foreach ($name in 'alpha', '', 'beta', 'stop', 'omega') {
if ([string]::IsNullOrWhiteSpace($name)) {
continue
}
if ($name -eq 'stop') {
break
}
Write-Output $name
}
Ausgabe:
alpha
beta
Beide sind keine allgemeinen Befehle zum Beenden eines Skripts. Außerhalb einer Schleife, von switch oder trap kann PowerShell im Aufrufstack nach einem umgebenden Konstrukt suchen und den aktuellen Runspace beenden, wenn keines existiert.
Einen anderen Prozess mit Stop-Process beenden
Stop-Process beendet einen separaten Prozess auf dem lokalen Computer, nicht das aktuelle Skript. Prüfen Sie eine breite Auswahl zuerst mit -WhatIf:
Get-Process -Name notepad -ErrorAction SilentlyContinue |
Stop-Process -WhatIf
Entfernen Sie -WhatIf erst, wenn die Ziele feststehen. Verwenden Sie möglichst ein bekanntes Prozessobjekt oder eine PID, falls ein Name mehrere Prozesse treffen kann. Für Prozesse eines anderen Benutzers kann außerdem eine erhöhte PowerShell-Sitzung erforderlich sein.
Exitcodes nativer Programme bewahren
$? zeigt den Erfolg des letzten PowerShell-Befehls an; $LASTEXITCODE enthält dagegen den Exitcode des letzten nativen Programms. Speichern Sie ihn sofort, weil der nächste native Befehl ihn überschreiben kann.
git status --porcelain
$gitCode = $LASTEXITCODE
if ($gitCode -ne 0) {
Write-Error "git failed with exit code $gitCode"
exit $gitCode
}
Aufräumen sicherstellen und Abbruch unterscheiden
Bewahren Sie Aufräumarbeiten in finally auf, nicht hinter einer Zeile, die die Verarbeitung beenden kann. Laut der Dokumentation zu PowerShell-Sprachschlüsselwörtern wird finally ausgeführt, ob der try-Teil erfolgreich ist, ein Fehler catch erreicht, exit aufgerufen wird oder Strg+C das Skript unterbricht. Daher eignet es sich zum Freigeben eines Streams, einer Sperre oder einer temporären Datei.
$stream = $null
try {
$stream = [System.IO.File]::OpenRead($Path)
# Process the stream.
}
finally {
if ($null -ne $stream) {
$stream.Dispose()
}
}
Lassen Sie wiederverwendbaren Code throw oder return an das Einstiegsskript übergeben, statt mitten in dieser Arbeit exit aufzurufen. So kann das Einstiegsskript aufräumen, eine Diagnose schreiben und den Prozessstatus an einer sichtbaren Stelle festlegen. Strg+C, ein angehaltener Job und ungültige Eingaben sind verschiedene Ereignisse: Legen Sie fest und dokumentieren Sie, ob jedes ein Abbruch, ein Validierungsfehler oder ein anderer Status ist, auf den Aufrufer oder Scheduler reagieren müssen. Fassen Sie sie nicht stillschweigend zu einem allgemeinen Fehler zusammen. Einen anderen Prozess zu beenden ist wieder etwas anderes; bevorzugen Sie dessen normale Beendigung. Stop-Process -Force kann Aufräumarbeiten verhindern und sollte nur bei verstandener Folge eingesetzt werden.
Kindskripte und Hosts im vorgesehenen Bereich halten
Der Aufrufoperator führt ein Kindskript in einem eigenen Skriptbereich aus. Dot-Sourcing führt ein Skript im aktuellen Bereich aus und importiert dessen Funktionen und Variablen. Nutzen Sie Dot-Sourcing nur, wenn dieses Importieren beabsichtigt ist.
# Run the child in its own script scope.
& .\Child.ps1
# Import definitions into the current scope.
. .\Functions.ps1
Ein exit in wiederverwendbarem Code ist stärker als return: Es kann die interaktive Sitzung, den Test-Runner oder einen anderen aufrufenden Host beenden. Die sichtbare Wirkung hängt außerdem vom Host ab. Ein mit powershell.exe -File oder pwsh -File gestarteter Kindprozess endet und gibt die Steuerung an den Aufrufer zurück; eine interaktive Konsole kann ihre aktuelle Sitzung schließen. Eingebettete Runspaces und Editoren können sich anders verhalten. Testen Sie die tatsächliche Produktionskommandozeile, einschließlich -File gegenüber -Command, Profilen, Quoting, Ausgabe und Exitstatus getrennt.
Empfehlung
Verwenden Sie exit <Code> nur an der bewussten Grenze des Hauptskripts, return für den aktuellen Bereich und throw für einen Fehler, den ein Aufrufer behandeln kann. Nutzen Sie break und continue, wenn die zugehörige Schleife oder switch sichtbar ist, und Stop-Process nur für einen separaten lokalen Prozess. Geschäftslogik in Funktionen, die zurückgeben oder Fehler auslösen, bleibt wiederverwendbar; ein kleines Einstiegsskript kann das Ergebnis dann in einen stabilen Status für Shell, Aufgabenplanung, CI oder Wrapper übersetzen.