PowerShell-Fallen #1: Die schwarze $null oder über den Strict Mode

Veröffentlicht am Kategorisiert in PowerShell Keine Kommentare zu PowerShell-Fallen #1: Die schwarze $null oder über den Strict Mode

Wer PowerShell lernt, stolpert häufig über Eigenarten der Sprache, die sich von jenen anderer bekannter Sprachen unterscheiden und darum zunächst überraschend sind. Hier möchte ich ein paar von ihnen hervorheben und erläutern, wie das oft eigentlich gewünschte Ergebnis erzielt werden kann.

Los geht’s mit dem Standardverhalten von PowerShell, wenn der Interpreter auf eine nicht deklarierte Variable stößt: Er löst sie einfach als $null auf!

$undeclared_variable -eq $null

Output:
True

Das kann in vielen Situationen praktisch sein, aber auch zu schwierig zu erkennenden Fehlern führen, wenn der Variablenname versehentlich falsch geschrieben wurde: Dann gibt eine if-Anweisung plötzlich $false zurück, weil mit $null anstatt mit dem Wert der richtigen Variable verglichen wird, und das Programm arbeitet ohne Warnung oder Fehlermeldung einfach weiter.

Wer lieber gleich auf die undeklarierte Variable hingewiesen werden möchte, muss den Strict Mode aktivieren, der das Programm mit einer Fehlermeldung beendet. Der Strict Mode ist in verschiedenen Versionen verfügbar:

Strict Mode Version 1.0

Set-StrictMode -Version 1.0
$undeclared_variable -eq $null

Output:
InvalidOperation: The variable '$undeclared_variable' cannot be retrieved because it has not been set.

In seiner einfachsten Form merkt der Strict Mode bloß, dass die Variable nicht existiert. Doch schon wenn die Variable in einem String eingesetzt wird, wird sie wieder als $null aufgelöst:

Set-StrictMode -Version 1.0
"Value between brackets: [$undeclared_variable]"

Output:
Value between brackets: []

Genauso ergeht es übrigens nicht existierenden Eigenschaften (während nicht existierende Methoden grundsätzlich terminierende Fehler aufwerfen):

Set-StrictMode -Version 1.0
$test = "hi there"
$test.NonExistingProperty -eq $null

Output:
True

Strict Mode Version 2.0

Set-StrictMode -Version 2.0
"Value between brackets: [$undeclared_variable]"

Output:
InvalidOperation: The variable '$undeclared_variable' cannot be retrieved because it has not been set.
Set-StrictMode -Version 2.0
$test = "hi there"
$test.NonExistingProperty -eq $null

Output:
PropertyNotFoundException: The property 'NonExistingProperty' cannot be found on this object. Verify that the property exists.

In Version 2.0 führen auch nicht gesetzte Variablen in Strings und nicht existierende Eigenschaften zu einem terminierenden Fehler.

Allerdings erlaubt er es auch nicht mehr, Funktionen mit mehreren Arguemnten mit der Syntax von Methoden aufzurufen – ein Stolperstein für alle, die mit anderen Programmiersprachen vertraut sind:

Set-StrictMode -Version 2.0

function Test {
    param(
    $arg1,
    $arg2
    )
    $arg1
    $arg2
}

Test("hi", "there")

Output:
InvalidOperation: The function or command was called as if it were a method. Parameters should be separated by spaces. For information about parameters, see the about_Parameters Help topic.

Korrekt ist folgende Schreibweise:

Test "hi" "there"

Output:
hi
there

Doch entgegen der Fehlermeldung lassen sich die Argumente in diesem Fall auch mit Komma trennen:

Test "hi", "there"

Output:
hi
there

Und wenn man Funktionsname und öffnende Klammer mit einem Leerzeichen trennt, wird zwar kein Fehler aufgeworfen, aber der Inhalt der Klammer wird als ein einziges argument und damit als $arg1 interpretiert, während $arg2 implizit als $null gesetzt wird:

Test ("hi, there")

Output:
hi, there

Strict Mode Version 3.0

Für Version 3.0 gilt ebenso alles für Version 2.0 Ausgeführte. Zusätzlich führen aber auch ungültige Indizes zu einem Fehler, während ältere Versionen wieder einmal $null zurückgaben:

Set-StrictMode -Version 3.0
$list = "apples", "oranges", "peaches"
$list[3]

Output:
OperationStopped: Index was outside the bounds of the array.

PowerShell versucht, Indizes notfalls in den Typ System.Int32 zu konvertieren ("002" zu 2), und wenn das nicht möglich ist, geben frühere Versionen … richtig, $null zurück. Nicht so mit Version 3.0:

Set-StrictMode -Version 3.0
$list = "apples", "oranges", "peaches"
$list["test"]

Output:
InvalidArgument: Cannot convert value "test" to type "System.Int32". Error: "Input string was not in a correct format."

Fazit

PowerShell ist von Natur aus sehr fehlertolerant und konvertiert gerne Fehlendes und Unmögliches zu $null. Das ist praktisch, aber auch eine mögliche und dann unter Umständen nicht offensichtliche Fehlerursache. Wer den Strict Mode einsetzt und später wieder ausschalten möchte, kann das natürlich auch tun:

Set-StrictMode -Off

Und wer immer den strengsten Modus anwenden möchte, wählt einfach Latest (Vorsicht, es könnte ja einmal Version 4.0 eingeführt werden):

Set-StrictMode -Version Latest

Von Pascal Korz

IT Systems Engineer in und aus dem schönen Köln

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert