Tags: PowerShell
Neben Arrays unterstützt PowerShell mit Hash-Tabellen einen weiteren zusammengesetzten Datentyp. Er bietet Methoden, um Schlüssel/Wert-Paare nachzuschlagen, hinzuzufügen, zu ändern oder zu löschen. Hashtables lassen sich vielfältig anwenden, etwa zur Übergabe von Werten an Cmdlet-Parameter.
Der wesentliche Unterschied zwischen gewöhnlichen Arrays und Hash-Tabellen, die auch assoziative Arrays heißen, besteht darin, dass man nicht bloß einen nummerischen Index, sondern jedes .NET-Objekt als Schlüssel verwenden kann. Hashtables bestehen somit aus einer Sammlung von Key/Value-Paaren.
Arrays versus Hashtables
Legt man etwa dieses Array an
$farben = @("Schwarz","Weiß","Gelb","Blau")
dann ruft man das zweite Element mit dem Wert "Weiß" über $farben[1] ab. Entsprechend kann man durch Hochzählen des Indexes einfach über das gesamte Feld iterieren (siehe dazu Arrays in PowerShell: anlegen, ändern, auslesen, sortieren, löschen).
Hashtables hingegen bestehen immer aus Paaren in der Form Schlüssel = Wert. Um beim Thema Farben zu bleiben, könnte eine Hash-Tabelle so aussehen:
$farben = @{Auto ="Schwarz"; Wand="Weiß"; Ei ="Gelb"; Himmel="Blau"}
Bei der Syntax zum Anlegen eines assoziativen Arrays ist zu beachten, dass die Key/Value-Paare in geschweiften Klammern stehen (beim normalen Array sind es runde) und durch Semikolon voneinander getrennt sind (beim Array ist auch ein Komma zulässig). Die Zuordnung des Werts zu einem Schlüssel erfolgt über das Gleichheitszeichen.
Auf Elemente zugreifen
Möchte man nun auf das zweite Element mit Wert "Weiß" zugreifen, dann bietet PowerShell dafür mehrere Möglichkeiten. Analog zu Arrays könnte man dies mit
$farben["Wand"]
tun. Wie man sieht, dient hier der Schlüssel "Wand" als Index und nicht ein nummerischer Wert (auch wenn sich ein solcher ohne weiteres als Key verwenden ließe).
Wie bei Arrays erlaubt PowerShell auch hier, mehrere Elemente auf einmal anzusprechen:
$farben["Auto", "Wand"]
Alternativ kann man die Notation
$farben.Wand
verwenden, oder wenn man es aufwändiger haben möchte, die Funktion Get_Item bemühen:
$farben.Get_Item("Wand")
Wenn man dabei kein Ergebnis erhält, dann kann entweder der Wert für diesen Key $null sein oder der Schlüssel existiert nicht. Um zu überprüfen, ob er vorhanden ist, verwendet man die Funktion ContainsKey:
$farben.ContainsKey("Wand")
Der Gegenspieler, die Funktion ContainsValue(), informiert dagegen, ob ein bestimmter Wert in der Tabelle vorliegt:
$farben.ContainsValue("Weiß")
Beide Funktionen geben True oder False zurück, abhängig davon, ob sie den gewünschten Wert finden.
Will man den gesamten Inhalt der Tabelle ausgeben, dann reicht wie in PowerShell üblich, die Eingabe des Variablennamens. Wie der Befehl
$farben | measure
jedoch zeigt, erhält man den ganzen Hashtable auf diese Weise als ein Objekt.
Wie viele Elemente er enthält, kann man aber wie bei einem Array über die Eigenschaft count erfahren:
$farben.count
würde in unserem Beispiel 4 ausgeben.
Über Hash-Tabellen iterieren
Bei verschiedenen Gelegenheiten wird man die gesamte Sammlung in einer Schleife durchlaufen wollen. Während man bei einem Array dafür nur den Index hochzählen muss, benötigt man hier ein anderes Verfahren.
Zum einen eignet sich dafür eine foreach-Schleife über alle Keys, wobei sie bei jedem Durchlauf eine zweite Variable mit dem aktuellen Schlüssel belegt:
foreach($k in $farben.Keys){ $farben[$k] }
Zum anderen bietet sich die Funktion GetEnumerator() für diese Aufgabe an, so dass man sich die Laufvariable sparen kann:
$farben.GetEnumerator() | foreach{ $_.value }
Möchte man alle Elemente finden, die einen bestimmten Wert haben, dann muss man nicht über das Dictionary iterieren, hier tut es auch ein Filter mit Where-Object (Alias "?"):
$farben.Keys | ? { $farben[$_] -eq "Weiß" }
Schlüssel hinzufügen
Wie ganz oben gezeigt, kann man gleich bei der Deklaration eines Hashtable die Schlüssel/Wert-Paare einfügen. Wenn man etwa mit einer leeren Hash-Tabelle
$farben=@{}
beginnt oder einfach zu bestehenden Keys weitere hinzufügen möchte, dann gibt es auch dafür mehrere Optionen. Die offensichtlichste folgt der gleichen Syntax wie bei der Deklaration:
$farben["Wiese"] = "Grün"
Darüber hinaus bietet eine Hash-Tabelle für diesen Zweck die Methode add():
$farben.Add("Wiese", "Grün")
Schließlich kann man für diese Aufgabe auch den Additionsoperator heranziehen:
$farben += @{Wiese = "Grün"}
Wie man unschwer erkennen kann, legt man hier für den neuen Schlüssel eine eigene Hash-Tabelle an. Somit handelt es sich dabei um ein Verfahren, mit dem man generell zwei assoziative Arrays kombinieren kann.
Schlüssel löschen
Um einen Key aus dem Dictionary zu entfernen, sieht PowerShell die Methode remove() vor. Damit lässt sich bei jedem Aufruf jeweils nur ein Paar löschen:
$farben.Remove("Wiese")
Komplizierter wird die Angelegenheit, wenn man über die Tabelle iterieren will, um Schlüssel zu löschen, die einen bestimmten Wert haben, im folgenden Beispiel wäre das "Grün":
$farben.GetEnumerator() |
%{ if($_.value -eq "Grün"){ $farben.remove($_.key)} }
Dieses Vorgehen quittiert PowerShell aber mit der Meldung "Fehler beim Durchlaufen einer Auflistung: Die Auflistung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden".
Wenn man diese Reaktion vermeiden und ein verlässliches Ergebnis erzielen will, dann hilft hier der Einsatz der Funktion clone(), um eine separate Referenz auf die Tabelle zu bekommen:
($farben.Clone()).GetEnumerator() |
foreach{ if($_.value -eq "Grün"){$farben.remove($_.key)} }
Wenn man alle Keys entfernen möchte, dann dient die Funktion clear() diesem Zweck:
$farben.Clear()
Hash-Tabelle sortieren
Ein naheliegender Ansatz könnte darin bestehen, die Ausgabe der Variablen über eine Pipe an Sort-Object zu übergeben:
$farben | sort #funktioniert nicht
Wie wir aber schon weiter oben gesehen haben, liefert die Eingabe des Variablennamens die gesamte Hash-Tabelle als ein Objekt zurück, ein Sortieren der Elemente ist daher so nicht zu erwarten.
Auch für das Sortieren muss man somit über das Dictionary iterieren, wobei sich wieder die Methode GetEnumerator() als nützlich erweist:
$farben.GetEnumerator() | sort -Property name
Dieses Beispiel sortiert die Elemente nach dem Schlüssel. Möchte man sie stattdessen nach den Werten ordnen, dann ersetzt man im obigen Aufruf name durch value.
Man könnte natürlich auf die Idee kommen, die Schlüssel beim Anlegen des Hashtables gleich in sortierter Reihenfolge einzugeben. Allerdings zeigt sich dann schnell, dass PowerShell diese Sortierung nicht beibehält und die Key/Value-Paare in beliebiger Reihenfolge ausgibt.
Dieses Verhalten kann man jedoch abstellen, indem man seit PowerShell 3.0 das Keyword [ordered] verwendet:
$farben = [ordered]@{Auto ="Schwarz"; Wand="Weiß"; Ei ="Gelb"; Himmel="Blau"}
Es ist allerdings nicht möglich, damit eine vorhandene Hash-Tabelle durch einen Cast in eine geordnete Sammlung zu konvertieren.
Splatting: Aufruf von Cmdlets mit Hashtable
Eine häufige Anwendung von Hash-Tabellen besteht darin, die Parameter und ihre Werte darin zu speichern, bevor man sie an ein Cmdlet übergibt. Gerade bei Cmdlets mit sehr vielen Parametern, beispielsweise New-ADUser, erreicht man dadurch einen deutlich übersichtlicheren Code.
Anstatt das Cmdlet wie üblich so aufzurufen:
New-ADUser -Name Max.Meier -GivenName Max -Surname Meier -Path "OU=Benutzer,DC=contoso,DC=Com"
könnte man folgendermaßen vorgehen:
Zu beachten ist hier, dass man dem Hashtable ein '@' und nicht ein '$' voranstellt.
Täglich Know-how für IT-Pros mit unserem Newsletter
Verwandte Beiträge
- Hyper-V Switch mit PowerShell erstellen, verwalten und löschen
- PowerShellGet-Modul aktualisieren, auf PSResourceGet umsteigen
- Adressbücher in Exchange Online anlegen und pflegen
- BitLocker aktivieren mit manage-bde, PowerShell oder WMI
- WhatIf, Confirm und Force: Ausführung von PowerShell-Cmdlets steuern
Weitere Links