PowerShell: Erkennen von Fehlern in Skriptfunktionen

7

Was ist der beste Weg, um festzustellen, ob ein Fehler in einer Skriptfunktion auftritt? Ich suche nach einem konsistenten Weg, um einen Fehler- / Erfolgsstatus ähnlich $ anzuzeigen. (Dies funktioniert nur mit Cmdlets, nicht mit Skriptfunktionen.)

Wenn eine bestimmte Funktion einen Wert zurückgibt, der vom Aufrufer verwendet werden soll, können wir keinen Erfolg angeben, indem wir einen booleschen Wert zurückgeben. Eine Funktion könnte einen [ref] -Parameter verwenden und den Wert in der Funktion entsprechend einstellen und nach dem Aufruf überprüfen, aber das ist mehr Overhead, als ich möchte. Gibt es in PowerShell etwas, das wir verwenden können?

Das Beste, was ich mir vorstellen kann, ist:

  1. In der Funktion Write-Error verwenden Setzen Sie ErrorRecord-Objekte in den Fehler streamen;
  2. rufe die Funktion mit einem ErrorVariable Parameter;
  3. Überprüfen Sie, ob der Parameter ErrorVariable vorhanden ist ist nach dem Anruf nicht null.

Zum Beispiel:

%Vor%

Gibt es etwas Besseres? Gibt es eine Möglichkeit, $ zu verwenden? in unseren Skriptfunktionen? Ich möchte lieber keine Exceptions oder ErrorRecord-Objekte werfen und habe Tonnen von Versuchs- / Catch-Blöcken überall. Ich würde auch lieber nicht $ Error verwenden, da es erforderlich wäre, die Zählung vor dem Funktionsaufruf zu überprüfen, da es vor dem Anruf andere Fehler geben könnte - und ich möchte nicht löschen () und sie verlieren.

    
DanW 21.06.2011, 18:44
quelle

6 Antworten

11
  

Was ist der beste Weg, um festzustellen, ob ein Fehler in einer Skriptfunktion auftritt? Ich suche nach einem konsistenten Weg, um einen Fehler- / Erfolgsstatus ähnlich $ anzuzeigen. (Dies funktioniert nur mit Cmdlets, nicht mit Skriptfunktionen.)

Fehlerbehandlung in PowerShell ist ein totales Durcheinander. Es gibt Fehlerdatensätze, Skriptausnahmen, .NET-Ausnahmen, $? , $LASTEXITCODE , trap s, $Error -Array (zwischen Bereichen) und so weiter. Und konstruiert, um diese Elemente miteinander zu interagieren (zB $ErrorActionPreference ). Es ist sehr schwierig, konsistent zu werden, wenn man einen solchen Morast hat; Es gibt jedoch einen Weg, dieses Ziel zu erreichen.

Die folgenden Beobachtungen müssen gemacht werden:

  • $? ist ein undokumentiertes Geheimnis. $? -Werte von Cmdlet-Aufrufen propagieren nicht, es ist eine "schreibgeschützte Variable" (kann also nicht von Hand gesetzt werden) und es ist nicht klar, wann genau gesetzt wird (was möglicherweise möglich ist ein "Ausführungsstatus" sein, ein Begriff, der nie in PowerShell verwendet wird, mit Ausnahme der Beschreibung von $? in about_Automatic_Variables , ist ein Rätsel). Erfreulicherweise hat Bruce Payette Folgendes herausgefunden: Wenn Sie $? einstellen wollen, ist $PSCmdlet.WriteError() der einzig bekannte Weg.

  • Wenn Funktionen $? als Cmdlets festlegen sollen, müssen Sie von Write-Error absehen und stattdessen $PSCmdlet.WriteError() verwenden. Write-Error und $PSCmdlet.WriteError() machen dasselbe, aber erstere setzt $? nicht richtig und letzteres. (Versuchen Sie nicht, dies irgendwo dokumentiert zu finden. Das ist es nicht.)

  • Wenn Sie .NET-Exceptions ordnungsgemäß behandeln möchten (als ob es sich um nicht terminierende Fehler handelt, die Entscheidung über die Ausführung der gesamten Ausführung bis zum Client-Code zu belassen), müssen Sie catch und $PSCmdlet.WriteError() sie verwenden . Sie können sie nicht unbearbeitet lassen, da sie zu nicht terminierenden Fehlern werden, die nicht für $ErrorActionPreference respektieren. (Nicht dokumentiert auch nicht.)

Mit anderen Worten, der Schlüssel zur Erzeugung eines konsistenten Fehlerbehandlungsverhaltens besteht darin, wann immer möglich $PSCmdlet.WriteError() zu verwenden. Er setzt $? , respektiert $ErrorActionPreference (und somit -ErrorAction ) und akzeptiert System.Management.Automation.ErrorRecord -Objekte, die von anderen Cmdlets erzeugt wurden oder eine catch -Anweisung (in der $_ -Variable).

Die folgenden Beispiele zeigen, wie diese Methode verwendet wird.

%Vor%

Als letzte Anmerkung, wenn Sie Abschlussfehler von .NET-Ausnahmen erstellen möchten, machen Sie try / catch und re throw die Ausnahme, die abgefangen wurde.

    
alecov 22.09.2014 17:35
quelle
6

Es scheint, als ob Sie nach einem allgemeinen Mechanismus suchen, um jeden Fehler zu protokollieren, der in einem Befehl auftritt, der von einem Skript aufgerufen wird. Wenn ja, ist trap wahrscheinlich der am besten geeignete Mechanismus:

%Vor%

Durch Ausführen dieses Testskripts wird die folgende Ausgabe erstellt, ohne dass die aufgerufenen Funktionen geändert werden müssen:

%Vor%

Wenn die Skriptausführung angehalten werden soll, nachdem ein Fehler gemeldet wurde, ersetzen Sie continue durch break im Trap-Handler.

    
Emperor XLII 17.12.2011 14:48
quelle
3

Es gibt zwei Dinge: Throw (besser als Write-Error in obigem Beispiel) und try..catch

%Vor%

Imho, es ist im Allgemeinen besser, die Funktion selbst zu haben, um ihre Fehler so gut wie möglich zu behandeln.

    
Torbjörn Bergstedt 21.06.2011 19:10
quelle
0

$? hängt davon ab, ob die Funktion einen Abbruchfehler erzeugt oder nicht. Wenn Write-Error verwendet wird, nicht Throw, $? ist nicht eingestellt. Viele Cmdlets setzen $ nicht? wenn sie einen Fehler haben, weil dieser Fehler kein Abbruchfehler ist.

Der einfachste Weg, Ihre Funktion auf $ setzen zu lassen? Verwenden Sie -ErrorAction Stop. Dies wird das Skript stoppen, wenn Ihre Funktion Fehler und $? wird eingestellt.

Beachten Sie diesen Beispielblock, um zu sehen, wie $? funktioniert:

%Vor%

Hoffe das hilft

    
Start-Automating 21.06.2011 20:27
quelle
0

Ich glaube, Sie wollen eine globale Variable $ GLOBAL: variable_name. Diese Variable wird nicht nur in der Funktion, sondern auch im Skript enthalten sein.

Wenn Sie sich den Code ansehen, können Sie auch trap ( Get-Help about_Trap ) verwenden - obwohl $ GLOBAL: variable_name mit Ihrer oben zusammen funktionieren würde. Hier ist eine Wiederholung des Codebeispiels - ich habe das nicht getestet, also ist es mehr Pseudocode ...:)

%Vor%

HTH, Matt

    
Matt 23.06.2011 05:59
quelle
0

Das meiste davon machte einen entzückenden Klang, als es direkt über meinen Kopf ging ... ಠ_ಠ

Ich bin bei Dan. PS Logging ist ein komplettes Chaos und scheint, als würde es die Größe des Codes, den ich schreibe, mehr als verdoppeln ...

Ehrlich gesagt, würde ich mich freuen, wenn ich die Konsolenausgabe direkt in Logs, Warzen und alles andere erfassen könnte ...

Der Try / Catch-Block ist so ... so ... beschissen, ich kann es riechen und es hat meine Augen braun werden lassen.

Das $? ist sehr interessant, aber ihr wisst eigentlich was du tust, als wo ich an dem Punkt bin wo ich merke dass ich nichts weiss (letzte Woche dachte ich ich wüsste wenigstens etwas, aber noooooo).

Warum ist das% $ # @% $ nicht so etwas wie das 2 & gt; in kli ...

Ok, hier ist, was ich versuche zu tun (Sie haben so weit gelesen, also warum nicht?):

%Vor%

Hat es funktioniert? Ja, gut ... Log es und fahre fort. Nein? Dann fangen Sie den Fehler ab, loggen Sie ihn ein und setzen Sie das Skript fort ...

Ich bin versucht, einfach nach Benutzereingaben zu fragen, add-content und fahre fort ...

Übrigens, ich habe ein PSLogging-Modul gefunden, das scheint ziemlich cool zu sein, aber ich bin mir nicht sicher, wie es funktioniert ... Die Dokumentation ist ein bisschen Spartanisch. Scheint so, als würden die Leute es ohne große Probleme in Gang bringen, also habe ich das Gefühl, dass ich eine Ecke bin, die einen spitzen Hut hat, eine Art Mensch ...

    
Marc Everlove 13.11.2017 21:44
quelle

Tags und Links