| | 0

PowerShell: Preference und Error Variable, Fehlerbehandlung – Part 13

3.12 Die Preference Variablen

Die sogenannten Preference Variablen (sozusagen, die Einstellungen für die Shell) beeinflussen das Verhalten der Shell. Sie können vom Benutzer in der laufenden Shell verändert oder fest über ein Profil eingestellt werden. Auch aus einem Skript heraus können diese Variablen verändert werden (Scope beachten). Einige von den Preference Variablen definieren auch das Verhalten von sogenannten „Common Parameters“ (siehe about_Common Parameters), welche mit fast jedem Cmdlet verwendet werden können. Detailliert werden diese Variablen und auch die möglichen Werte in dem Hilfethema About_Preference_Variables beschrieben. Hier sei nur auf ein paar Beispiele eingegangen:

 

Preference Variable Bedeutung
$ErrorActionPreference Legt fest, wie sich die Shell bei nicht kritischen Fehlern verhält. Mögliche Werte sind:

Stop                         unmittelbar abbrechen

Inquire                     nach Aktion fragen

Continue                  Fehler anzeigen und fortfahren

SilentlyContinue      Fehler nicht anzeigen und fortfahren

$MaximumErrorCount Anzahl der Fehler, welche in der Variablen $Error gespeichert werden (siehe Kapitel 3.13). Standard ist 256, Maximum Int32
$MaximumFunction-Count Die maximale Anzahl von Funktionen in einer Shellinstanz. Standard ist 4096, Maximum Int32
$MaximumHistoryCount Die maximale Anzahl von in der Shell eingegebenen Befehlen, die mit den Pfeiltasten oder der F7 Taste wiederholt werden können. Standardwert 64, Maximum Int32
$MaximumVariableCount Die maximale Anzahl von Variablen in einer Shellinstanz. Standard 4096, Maximum Int32
$OFS Output Field Separator. Das dort gespeicherte Zeichen wird bei der Ausgabe eines Arrays nach einer Konvertierung in String verwendet. Standard ist Leerzeichen. Es kann eine beliebige Zeichenfolge verwendet werden:

1
2
3
4
5
6
7
1.  [String]@(1..5)
1 2 3 4 5
2.  $OFS = „###“
3.  [String]@(1..5)
1###2###3###4###5

3.13 Die Error-Variable, Fehlerbehandlung

In den meisten Shells und Skriptsprachen stehen Informationen über Fehler nur rudimentär zur Verfügung. Ein Fehlercode und eine Fehlerbeschreibung in Form von einem String ist das höchste der Gefühle. In der PowerShell ist natürlich auch das anders. Hier werden keine bloßen Strings und Zahlen im Fehlerfall erzeugt, sondern Objekte, sogenannte ErrorRecords. Diese werden in einer Variablen mit dem Namen $Error gespeichert. Es handelt sich um eine Array* Variable, deren Elemente die ErrorRecords sind. Die Fehler werden dort bis zu einer Anzahl von $MaximumErrorCount abgelegt. Wenn die Obergrenze erreicht ist, funktioniert die $Error Variable wie ein FIFO Puffer. Der letzte Fehler ist immer an der ersten Position gespeichert (Index 0). Das bedeutet, dass die Informationen zu Fehlern nicht nur unmittelbar nach dem Auftreten eines solchen, sondern wesentlich länger, zur Verfügung stehen. Welche Informationen sind von einem ErrorRecord zu erwarten? Ein Beispiel soll das verdeutlichen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1.  get-childitem marius.txt
Get-ChildItem : Cannot find path 'X:\Temp\marius.txt' because it does not exist.
At line:1 char:14
+ get-childitem <<<<  marius.txt
    + CategoryInfo          : ObjectNotFound: (X:\Temp\marius.txt:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNot-Found,Microsoft.PowerShell.Commands.GetChildItemCommand
2.  $error.count
1
3.  $error[0] | format-list * -force
PSMessageDetails      :
Exception             : System.Management.Automation.ItemNotFoundException: Cannot find…
TargetObject          : X:\Temp\marius.txt
CategoryInfo          : ObjectNotFound: (X:\Temp\marius.txt:String) [Get-ChildItem], Ite…
FullyQualifiedErrorId : PathNot-Found,Microsoft.PowerShell.Commands.GetChildItemCommand
ErrorDetails          :
InvocationInfo        : System.Management.Automation.InvocationInfo
PipelineIterationInfo : {0, 1}
4.  $error[0] | get-member -type property
   TypeName: System.Management.Automation.ErrorRecord
Name                  MemberType Definition
----                  ---------- ----------
CategoryInfo          Property   System.Management.Automation.ErrorCategoryInfo Catego…
ErrorDetails          Property   System.Management.Automation.ErrorDetails ErrorDe-tails…
Exception             Property   System.Exception Exception {get;}
FullyQualifiedErrorId Property   System.String FullyQualifiedErrorId {get;}
InvocationInfo        Property   System.Management.Automation.InvocationInfo In-vocati…
PipelineIterationInfo Property   Sytem.Collections.ObjectModel.ReadOnlyCollection`1[[Sy…
TargetObject          Property   System.Object TargetObject {get;}

*Genau genommen ist das eine Collection vom Typ ArrayList, was aber in dieser Betrachtung keine große Rolle spielt, außer dass $Error ein paar Methoden und Eigenschaften hat, welche bei einem reinen Array nicht zu finden sind.

 

Die erste Zeile erzeugt einen Fehler, vorausgesetzt, die Datei „marius.txt“ existiert im aktuellen Verzeichnis nicht. In der Zeile zwei wird die Eigenschaft „Count“ der $Error Variablen abgefragt. Sie speichert die Fehler der Laufenden Sitzung und kann höchstens $MaximumErrorCount Elemente aufnehmen. In der Zeile drei werden die Details zum letzten Fehler angezeigt. In der Zeile vier werden schließlich die Eigenschaften des ErrorRecords angezeigt. Mit all diesen Informationen an der Hand sind die Fehlersuche und die Fehlerbehandlung in Skripten und innerhalb der Konsole wesentlich einfacher. Es gibt dennoch ein paar Stolperfallen. Ein Problem ergibt sich dann, wenn im Skript überprüft wird, ob ein Fehler aufgetreten ist, indem die Anzahl der Fehler vor und nach einer Aktion überprüft wird. Grundsätzlich wäre so ein Vorgehen nicht falsch. Allerdings würde die Prüfung versagen, wenn die Anzahl der Fehler bereits das Maximum erreicht hat… Ein Ausweg aus diesem Dilemma wäre, vor der fraglichen Aktion die $Error Variable zu bereinigen, was mit $Error.Clear() geht. Optimal wäre diese Vorgehensweise aber trotzdem nicht. Viel eleganter ist es, die automatische Variable $? abzufragen. Ist der Wert $False, hat der vorangegangene Befehl einen Fehler verursacht, ansonsten nicht.

So lange es sich um PowerShell Cmdlets oder Funktionen handelt, kann die Auswertung der Variablen $? ausreichend sein. Nähere Informationen sind in dem dazugehörigen ErrorRecord zu finden. Was aber, wenn externe Befehle oder Skripts ausgeführt werden? Für solche Fälle gibt es noch die Variable $LastExitCode. Sie speichert den Exitcode des externen Programms oder Skriptes und kann unmittelbar nach der Ausführung abgefragt werden. In diesem Fall wird zwar kein ErrorRecord in der Variablen $Error erzeugt, aber immerhin kann auf eine fehlerhafte Ausführung reagiert werden.

 

Ein Nachteil der Variablen $Error ist die Tatsache, dass sie wirklich alle Fehler speichert. Soll für eine bestimmte Aktion eine Fehlerauswertung durchgeführt werden, muss trotzdem mit der ganzen $Error Variablen herumhantiert werden. Es gibt aber noch zwei weitere Möglichkeiten, die Fehler zu einer be-stimmten Aktion gesondert abzuspeichern. Die erste erinnert etwas an die CMD Shell:

$err = .{dir | Foreach-Object {1/$null}} 2>&1

Hier werden alle Fehler in die Variable $err umgeleitet. Eine weitere Möglichkeit besteht darin, auf sogenannte Common Parameters zurück zu greifen (siehe auch Tabelle 3 2). Mit dem Parameter -ErrorVariable kann der Name einer Variablen angegeben werden, welche die möglicherweise aufgetretenen Fehler aufnimmt. Die Verwendung eines Pluszeichens vor dem Variablennamen (hier kein $-Zeichen) bewirkt, dass mehrere Fehler (durch Anhängen) in dieser Variablen gespeichert werden. In diesem Zusammenhang kann noch der Parameter –ErrorAction erwähnt werden. Wird dieser mit dem Argument „SilentlyContinue“ verwendet, werden keine Fehlerausgaben auf dem Bildschirm angezeigt.

Eine äußerst elegante Methode für die Behandlung von Fehlern bietet das Sprachkonstrukt Try…Catch…Finally. Allerdings ist es lediglich für die Behandlung von **terminierenden Fehlern  (.Net Exceptions) gedacht. Eine nähere Beschreibung mit Beispielen ist im Kapitel 4.4.12 zu finden.

**Terminierende Fehler sind solche, die einen Abbruch der Skript- oder Funktionsausführung zur Folge haben.

Weiter zu Part 14 – Skripte, Funktionen und Skriptblöcke (Einführung)

Zurück zu Part 12 – Die Shell

Eine Übersicht aller Artikel dieser Windows PowerShell Blogserie findet ihr hier.