Als ich mir ein Get-WebFile-Skript auf PoshCode ansah, http://poshcode.org/3226 , bemerkte ich diese für mich seltsame Erfindung:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
Was ist der Grund dafür im Gegensatz zu den folgenden?
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
Oder noch besser:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Soweit ich weiß, sollten Sie Write-Error verwenden, um Fehler nicht zu beenden, und Throw, um Fehler zu beenden. Aus diesem Grund sollte Write-Error gefolgt von Return nicht verwendet werden. Ist da ein Unterschied?
Write-Error
sollte verwendet werden, wenn Sie den Benutzer über einen nicht kritischen Fehler informieren möchten. Standardmäßig wird lediglich eine Fehlermeldung in roter Schrift auf der Konsole ausgegeben. Die Fortsetzung einer Pipeline oder einer Schleife wird nicht gestoppt. Throw
hingegen erzeugt einen sogenannten Abbruchfehler. Wenn Sie throw verwenden, wird die Pipeline und/oder die aktuelle Schleife beendet. Tatsächlich wird jede Ausführung abgebrochen, es sei denn, Sie verwenden ein trap
oder ein try/catch
Struktur zur Behandlung des Abbruchfehlers.
Es gibt eine Sache zu beachten, wenn Sie $ErrorActionPreference
bis "Stop"
und benutze Write-Error
es wird ein Abbruchfehler erzeugt.
In dem von Ihnen verlinkten Skript finden wir Folgendes:
if ($url.Contains("http")) {
$request = [System.Net.HttpWebRequest]::Create($url)
}
else {
$URL_Format_Error = [string]"Connection protocol not specified. Recommended action: Try again using protocol (for example 'http://" + $url + "') instead. Function aborting..."
Write-Error $URL_Format_Error
return
}
Offenbar wollte der Autor dieser Funktion die Ausführung dieser Funktion stoppen und eine Fehlermeldung auf dem Bildschirm anzeigen, wollte jedoch nicht, dass das gesamte Skript nicht mehr ausgeführt wird. Der Autor des Skripts hätte throw
verwenden können, dies würde jedoch bedeuten, dass Sie ein try/catch
beim Aufruf der Funktion.
return
beendet den aktuellen Bereich, der eine Funktion, ein Skript oder ein Skriptblock sein kann. Dies lässt sich am besten mit Code veranschaulichen:
# A foreach loop.
foreach ( $i in (1..10) ) { Write-Host $i ; if ($i -eq 5) { return } }
# A for loop.
for ($i = 1; $i -le 10; $i++) { Write-Host $i ; if ($i -eq 5) { return } }
Ausgabe für beide:
1
2
3
4
5
Ein Punkt hier ist die Verwendung von return
mit ForEach-Object
. Die Verarbeitung wird nicht wie erwartet unterbrochen.
Mehr Informationen:
$ErrorActionPreference
: about_Preference_Variablestry/catch
: about_Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_ReturnDer Hauptunterschied zwischen dem Cmdlet Schreibfehler und dem Schlüsselwort throw in PowerShell besteht darin, dass das vorherige einfach gedruckt wird etwas Text zum Standardfehlerstrom (stderr) , während letzterer tatsächlich die Verarbeitung des laufenden Befehls beendet oder Funktion, die then von PowerShell verarbeitet wird, indem Informationen über den Fehler an die Konsole gesendet werden.
Sie können das unterschiedliche Verhalten der beiden in den Beispielen beobachten, die Sie bereitgestellt haben:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
In diesem Beispiel wurde das Schlüsselwort return
hinzugefügt, um explizit die Ausführung des Skripts zu stoppen, nachdem die Fehlermeldung an die Konsole gesendet wurde. Im zweiten Beispiel hingegen ist das Schlüsselwort return
nicht erforderlich, da die Beendigung implizit durch throw
erfolgt:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Wichtig : Es gibt 2 Arten von Abschlussfehlern , Was die aktuellen Hilfethemen leider verschmelzen :
Anweisung - Beenden von Fehlern, wie sie von Cmdlets in bestimmten nicht behebbaren Situationen und von Ausdrücken gemeldet werden, in denen eine .NET-Ausnahme/eine PS-Laufzeit auftritt Fehler tritt auf; nur die Anweisung wird beendet und die Skriptausführung wird standardmäßig fortgesetzt .
Skript - Beenden von Fehlern, die entweder durch Throw
oder durch Eskalation eines der anderen Fehlertypen durch eine Fehleraktion ausgelöst wurden Präferenzvariable/Parameterwert Stop
.
Sofern sie nicht abgefangen werden, beenden sie den aktuellen Ausführungsthread (d. H. Nicht nur das aktuelle Skript, sondern gegebenenfalls auch alle seine Aufrufer).
Eine umfassende Übersicht über die Fehlerbehandlung in PowerShell finden Sie unter dieses GitHub-Dokumentationsproblem .
Der Rest dieses Beitrags konzentriert sich auf nicht-terminierende vs. Anweisungs-terminierende Fehler.
Ergänzen Sie die vorhandenen hilfreichen Antworten mit einem Fokus auf den Kern der Frage: Wie können Sie wählen ob Sie eine Aussage melden - beenden oder nicht beenden error ?
Cmdlet Error Reporting enthält hilfreiche Richtlinien; Lassen Sie mich eine pragmatische Zusammenfassung versuchen :
Die allgemeine Idee hinter nicht abschließenden Fehlern besteht darin, eine "fehlertolerante" Verarbeitung großer Eingabesätze zu ermöglichen : Fehler beim Verarbeiten einer Teilmenge von Die Eingabeobjekte sollten (standardmäßig) den - möglicherweise lang andauernden - Prozess nicht als Ganzes abbrechen, sodass Sie die Fehler überprüfen und nur die fehlgeschlagenen Objekte später erneut verarbeiten können - wie über die in der automatischen Variablen $Error
gesammelten Fehlersätze gemeldet.
Melden Sie einen NICHT TERMINIERENDEN Fehler, wenn Ihr Cmdlet/Ihre erweiterte Funktion:
$PSCmdlet.WriteError()
, um einen nicht beendenden Fehler zu melden (Write-Error
Führt leider nicht dazu, dass $?
In auf $False
Gesetzt wird der Aufrufer Umfang - siehe dieses GitHub-Problem ).$?
Gibt an, ob der letzte Befehl mindestens einen nicht beendenden Fehler gemeldet hat. $?
Als $False
Bedeuten, dass eine beliebige (nicht leere) Teilmenge von Eingabeobjekten nicht ordnungsgemäß verarbeitet wurde, möglicherweise die gesamte Menge.$ErrorActionPreference
Und/oder der allgemeine Cmdlet-Parameter -ErrorAction
Können das Verhalten von nicht beendenden Fehlern (nur) in Bezug auf das Fehlerausgabeverhalten ändern und festlegen, ob nicht beendende Fehler zu eskaliert werden sollen. script - terminating ones.Melden Sie einen STATEMENT-TERMINATING Fehler in allen anderen Fällen .
$PSCmdlet.ThrowTerminatingError()
verwenden, um einen anweisungsbeendenden Fehler zu generieren.Throw
im Gegensatz dazu einen Skript - Abbruchfehler generiert, der das gesamte Skript (technisch: das aktuelle Thread ) abbricht.try/catch
- Handler oder eine trap
- Anweisung verwendet werden (die nicht kann mit nichtbeendigenden Fehlern verwendet werden). Beachten Sie jedoch, dass selbst Anweisungsfehler - standardmäßig die Ausführung des restlichen Skripts nicht verhindern. Wie bei non-terminating errors gibt $?
$False
Wieder, wenn die vorherige Anweisung einen Fehler beim Beenden der Anweisung ausgelöst hat.Leider halten sich nicht alle PowerShell-eigenen Core-Cmdlets an diese Regeln :
Obwohl dies unwahrscheinlich ist, würde New-TemporaryFile
(PSv5 +) einen nicht beendenden Fehler melden, wenn er fehlschlägt, obwohl keine Pipelineeingabe akzeptiert und nur ein one output-Objekt erstellt wird. Dies wird sich jedoch wahrscheinlich in Version 6 ändern: siehe - diese GitHub Ausgabe .
Die Hilfe von Resume-Job
Behauptet, dass die Übergabe eines nicht unterstützten Auftragstyps (z. B. eines mit Start-Job
Erstellten Auftrags) nicht unterstützt wird, da Resume-Job
Nur für workflow gilt. jobs) verursacht einen Abbruchfehler, der jedoch ab PSv5.1 nicht mehr zutrifft.
Mit Write-Error
Kann der Verbraucher der Funktion die Fehlermeldung mit -ErrorAction SilentlyContinue
Unterdrücken (alternativ -ea 0
). Während throw
einen try{...} catch {..}
Benötigt
Um einen Versuch zu machen ... fange mit Write-Error
:
try {
SomeFunction -ErrorAction Stop
}
catch {
DoSomething
}
Ergänzung zu Andy Arismendis Antwort :
Ob Schreibfehler den Vorgang beendet oder nicht, hängt vom $ErrorActionPreference
Einstellung.
Bei nicht trivialen Skripten wird $ErrorActionPreference = "Stop"
ist ein empfohlene Einstellung , um schnell zu versagen.
"Das Standardverhalten von PowerShell in Bezug auf Fehler, das bei einem Fehler fortgesetzt werden soll, fühlt sich sehr VB6" On Error Resume Next "an."
(von http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
Es macht jedoch Write-Error
Anrufe werden beendet.
Um Schreibfehler als nicht beendenden Befehl unabhängig von anderen Umgebungseinstellungen zu verwenden, können Sie allgemeiner Parameter-ErrorAction
mit Wert Continue
:
Write-Error "Error Message" -ErrorAction:Continue
Wenn Sie den Code richtig gelesen haben, sind Sie richtig. Zum Beenden von Fehlern sollte throw
verwendet werden. Wenn Sie mit .NET-Typen arbeiten, ist es hilfreich, auch .NET-Ausnahmekonventionen zu befolgen.