Tags: PowerShell, Troubleshooting
Entwickler sollten sicherstellen, dass Scripts beim Auftreten von Fehlern nicht abrupt abbrechen, sondern kontrolliert enden. Benutzerfreundlicher Code verschont zudem User vor technischen Fehlermeldungen. PowerShell bietet die Mittel für ein differenziertes Error-Handling.
Grundsätzlich kann ein defensiver Programmierstil ein Script in vielen Situationen vor dem Scheitern bewahren. Daher sollten bestimmte Voraussetzungen nicht einfach als gegeben erachtet werden. Beispielsweise ist es meist ratsam, die Existenz von Dateien oder Rechnern im Netz zu prüfen, bevor man darauf zugreift. Auch eine erforderliche Version von PowerShell kann man abfragen.
Zwei Typen von Fehlern
Allerdings lassen sich nicht alle Bedingungen vorhersehen, unter denen ein Script ausgeführt wird. Entsprechend können Fehler auftreten, auf die der Code nicht vorbereitet ist. Aber in dieser Situation helfen Mechanismen für die Fehlerbehandlung, die Ausführung geordnet zu beenden.
PowerShell kennt grundsätzlich zwei Arten von Fehlern: Solche, die zum sofortigen Abbruch eines Kommandos oder Scripts führen ("Terminating Errors") und solche, die eine Fortsetzung erlauben ("Non-Terminating Errors").
Möchte man etwa Ereignisse in eine Log-Datei auf einem Laufwerk schreiben, das nicht existiert, dann gibt PowerShell standardmäßig den entsprechenden Fehler in roter Schrift auf dem Bildschirm aus und fährt mit der nächsten Anweisung fort.
Hingegen führen beispielsweise syntaktische Fehler im Code zum Abbruch des Scripts. Vergisst man etwa die schließende Klammer in einem Anweisungsblock oder ein Anführungszeichen am Ende eines Strings, dann tritt dieser Fall ein.
Behandlung von nicht-terminierenden Fehlern
Für beide Typen von Fehlern bietet PowerShell eigene Mechanismen, um das Verhalten von Scripts zu steuern. Die Möglichkeiten bei nicht-terminierenden Fehlern reichen vom Ignorieren und dem Unterdrücken der Meldungen bis hin zu einer Eskalation, so dass sie sich wie terminierende Fehler verhalten.
Im einfachsten Fall teilt man einem Cmdlet über den Parameter ErrorAction mit, wie es auf solche Situationen reagieren soll. Mögliche Werte dafür sind:
- SilentlyContinue: Die Fehlermeldung wird unterdrückt und PowerShell fährt mit der Ausführung des Codes fort
- Ignore (seit Version 3): Der Fehler wird ignoriert und taucht nicht im Error-Stream auf.
- Continue: Dabei handelt es sich um das Standardverhalten. Fehlermeldungen werden (in roter Schrift) ausgegeben und das Script setzt seine Ausführung fort.
- Stop: Erzwingt ein Verhalten wie bei einem terminierenden Fehler, die Ausführung wird also abgebrochen.
- Inquire: Fragt den Benutzer, ob er die Ausführung fortsetzen möchte.
Ein Aufruf könnte so aussehen:
gci -r -force -include *.tmp -ErrorAction SilentlyContinue $env:USERPROFILE
In diesem Beispiel würde keine Fehlermeldung ausgegeben, wenn der Benutzer, in dessen Kontext das Kommando läuft, keinen Zugriff auf einzelne Unterverzeichnisse seines Profils hat.
Reaktion über $ErrorActionPreference steuern
Möchte man das Verhalten von PowerShell bei Fehlern nicht nur für einen Befehl, sondern für alle nachfolgenden Kommandos ändern, dann bietet sich dafür die Variable $ErrorActionPreference an. Ihr weist man einen der oben erläuterten Werte zu, der Wert Ignore wird dabei aber nicht unterstützt:
$ErrorActionPreference = "SilentlyContinue"
In diesem Beispiel würden die darauf folgenden Anweisungen bei einem Fehler keine Meldung auf dem Bildschirm ausgeben. PowerShell speichert sie aber in dem Array $error, so dass man sie nachträglich inspizieren kann.
Variable $error auslesen
So ließen sich für alle aufgetretenen Fehler die Eigenschaften CategoryInfo und Exception auf diese Weise anzeigen.
$error | %{$_ | select CategoryInfo, Exception | fl}
Die Zahl der gespeicherten Fehler ist identisch mit der Länge des Arrays und lässt sich mithin so abfragen:
$error.Count
Terminierende Fehler abfangen mit try/catch
Die genannten Optionen für ErrorAction und $ErrorActionPreference haben keinen Einfluss auf das Verhalten bei terminierenden Fehlern. Möchte man verhindern, dass diese zum unkontrollierten Ende eines Scripts führen, dann fängt man sie in einem try/catch-Konstrukt ab.
Dieses ist folgendermaßen aufgebaut:
Der catch-Block dient meistens für irgendwelche "Aufräumarbeiten", beispielsweise um Änderungen vor dem Ende des Scripts rückgängig zu machen.
PowerShell erlaubt die Verwendung mehrerer catch-Blöcke, wobei dann jeder für einen anderen Typ von Exception zuständig ist. In diesem Fall muss man den Namen der jeweiligen Ausnahme in eckigen Klammern angeben:
Der hier benötigte Name der Exception lässt sich aus der $error-Variable auslesen, für den ersten Fehler im Speicher ginge das so:
$error[0].Exception.GetType().FullName
Wie erwähnt, fangen catch-Blöcke normalerweise keine nicht-terminierenden Fehler ab. Das kann man jedoch ändern, indem man $ErrorActionPreference auf Stop setzt.
Täglich Know-how für IT-Pros mit unserem Newsletter
Verwandte Beiträge
- Welche lokalen Gruppenrichtlinien sind auf dem Rechner aktiviert?
- Resolve-DnsName: nslookup für PowerShell
- Windows-Sicherheit öffnet sich nicht: Store-App mit PowerShell zurücksetzen
- Updates in WSUS importieren mit Internet Explorer oder PowerShell
- WSUS-Speicherplatz zurückgewinnen: Alte und ersetzte Updates löschen
Weitere Links
1 Kommentar
Wenn innerhalb eines Konstruktors festgestellt wird, dass die übergebenen Parameter logisch als nicht korrekt einzustufen sind (d. h. kein Absturz oder über try/catch aufgefangen), wie kann der Konstruktor die laufende Instanziierung beenden und das Ergebnis dem Aufrufer zur Kenntnis bringen (es gibt ja kein "return $null o. Ä.)? Das Ergebnis der Instanziierung soll also "keine Instanziierung" sein.