PowerShell und Arrays
Oft muss man sich zwischen Arrays und Hashtables entscheiden. Eine Hashtable bietet natürlich einen schnellen direkten Zugriff auf ein individuelles Element, wenn man den "Key" dazu nutzt. Dieser muss dann aber auch eindeutig sein. Ein Arrays ist eine Liste, in der Elemente auch mehrfach vorkommen können. Sobald ein Array dann zweidimensional ist, entspricht es eher einer Tabelle.
Das einfache Array
Ein einfaches "Array" mit Werten ist aber relativ unspektakulär. Hier definiere ich eine Variable und belege sie gleich
PS C:\> [int[]]$table PS C:\> $table=1,2,3,4 PS C:\> $table 1 2 3 4
Es geht natürlich auch in einer Zeile
[int[]] $table1 = 1,2,3,4,5,6,7,8,9
Ein Array kann aber auch durch den Kurzcode "@()" erstellt werden.
$status = @("OK","WARN","ERROR","FAIL",0)
Dabei muss nicht mal der Typ identisch sein
PS C:\> 0..4 | %{$status[$_].gettype()} IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object True True String System.Object True True String System.Object True True String System.Object True True Int32 System.ValueType
Das müssen Sie natürlich bei der weiteren Betrachtung berücksichtigen.
Eine Tabelle als Array
Interessant wird ein Array, wenn jede Zeile selbst ein PSObject darstellt und man diese einfach aneinander ketten kann:
[array]$result=@() $result+= [pscustomobject][ordered]@{Vorname = "Frank"; Nachname = "Carius"} $result+= [pscustomobject][ordered]@{Vorname = "Uwe"; Nachname = "Ulbrich"} $result Vorname Nachname ------- -------- Frank Carius Uwe Ulbrich
So schnell kann man dann eine Liste aufbauen, die mit Export-CSV etc. Natürlich auch sehr einfach ausgegeben und weiter verarbeitet werden kann. Einträge können hier im Gegensatz zur Hashtable auch mehrfach erscheinen. Allerdings ist ein Array in der Regel "Statisch", wie man mit einer Abfrage auch sehen kann.
$result.isfixedsize true
Ein Zugriff mit der ADD oder REMOVE-Methode funktioniert nicht. Irritierend kann aber sein, dass ein Erweitern mit "+=" dennoch möglich ist. So ganz konsistent ist das nicht.
Beim Export-CSV werden die Feldnamen des ersten Eintrags als Tabellenüberschrift genutzt.
"+=" Nachteile
Sie haben im vorherigen Abschnitt gesehen, dass ich ein Array erweitern kann. Hier noch mal ein Beispiel:
$MyArray=@() foreach ($count in (1..1000)) { $MyArray += $count } $MyArray.count
Das sieht einfach und verständlich aus. Wir würden Sie aber in dem Fall die Speicherverwaltung machen? Der Compiler/Interpreter weiß ja gar nicht, wie lange das Array noch wird. Ein Array ist aber ein statisches Element und im Hintergrund wird die PowerShell bei jedem "+=" ein neues Array anlegen und das alte Array kopieren, Wir brauchen temporär also doppelt so viel Speicher und es dauert auch noch länger. Leider hat die frühere PowerShell das so unglücklich gehandhabt. Sie sollten also genau überlegen, ob die "+="-Konstruktion für ihren Code passend ist. Es gibt nämlich auch Alternativen.
-
PowerShell
Hashtabellen
In den meisten Fällen speichere ich in Arrays z.B. AD-Benutzer und andre Objekte. Da kommt es mir eh nicht auf die Reihenfolge an, sondern ich habe einen primären Schlüssel, den ich eh zum direkten Zugriff brauche. Warum sollte ich ein mehrdimensionales Array mit "$myarray | where {$_ -eq <Wert>" durchsuchen, wenn ich direkt auf "$myhashtable[<key>]" zugreifen kann. - Array besser befüllen
Ich kann natürlich auch eine Konstruktion nutzen, die gleich ein Array liefert. Wenn ich den Code in eine Funktion packe, die alle Ausgaben einfach in die Pipeline sendet, dann reicht ein "$myarray = <funktionsname>" - GenericList
Mit ganz geringem Mehraufwand können Sie über "Arraylist" oder "GenericList" auch dynamisch erweiterbare Arrays erstellen, die über "add()" neue Element aufnehmen können
Nur das klassische statische Array ist zwar beim Programmieren mal schnell zusammengetippt aber ineffektiv hinsichtlich Speicher und Laufzeit.
Mit PowerShell 7.5. soll sich das Verhalten etwas verbessern.
- Improve Array BinaryAdd Method for
object[]
https://github.com/PowerShell/PowerShell/pull/23901 - Building Arrays and Collections in
PowerShell
https://vexx32.github.io/2020/02/15/Building-Arrays-Collections/ - Das Problem mit Array += in PowerShell
https://diecknet.de/de/2024/09/12/powershell-array-plus/
Arraylist oder GenericList
Microsoft rät mittlerweile davon ab, die
Klasse "Arraylist" zu nutzen
https://docs.microsoft.com/en-us/dotnet/api/system.collections.arraylist?redirectedfrom=MSDN&view=netframework-4.8#remarks
https://stackoverflow.com/questions/2309694/arraylist-vs-list-in-c-sharp
BBesser ist nur Nutzung der generischen Listen "[generic.list]"
Stattdessen kann eine "GenericList" genutzt werden
- List<T> Class
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1 - System.Collections.Generic Namespace
https://learn.microsoft.com/de-de/dotnet/api/system.collections.generic - Generic List Collection in C#
https://dotnettutorials.net/lesson/list-collection-csharp/
$MyArray=[Collections.Generic.List[PSObject]]::new() foreach ($count in (1..1000)) { $MyArray.add($count) } $MyArray.count
Die folgenden älteren Beispiele für eine Arraylist sind auch für eine Generic List nutzbar. Hier kann dann auch mit ADD und REMOVE gearbeitet werden.
PS C:\> [System.Collections.ArrayList]$ArrayList=@() PS C:\> $ArrayList.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True ArrayList System.Object PS C:\> $ArrayList.add("Frank") 0 PS C:\> $ArrayList.add("Carsten") 1 PS C:\> $ArrayList Frank Carsten PS C:\> $ArrayList.remove("Otto")
Beim "Add" wird als Rückgabe die aktuell Größe ausgegeben. Ein Remove eines nicht vorhandenen Elements liefert keine Fehlermeldung. Es ist auch nicht vorgeschrieben, dass die Elemente der Liste vom gleichen Typ sind. Das kann schon "verwirren", wie das folgende Beispiel zeigt, indem ich ein "Array" als drittes Element addiere
PS C:\> $ArrayList.add((1,2)) 2 PS C:\> $ArrayList Frank Carsten 1 2 PS C:\> $ArrayList.Count 3
Bei der Ausgabe sieht es aus, also ob hier vier Elemente drin sind. Real sind es aber nur drei, bei der Powershell das dritte Element entsprechend ausgibt. Wer aber Element für Element durchläuft, bekommt die Information schon einzeln
PS C:\> $ArrayList[2] 1 2
- ArrayList Class
https://msdn.microsoft.com/de-de/library/system.collections.arraylist(v=vs.110).aspx - Adding and Removing Items
from a PowerShell Array
http://www.jonathanmedd.net/2014/01/adding-and-removing-items-from-a-PowerShell-array.html
Arrays in Funktionen
Etwas Vorsicht ist bei der Verwendung von Arrays als Rückgabe von Funktionen zu beachten. Der folgende Beispielcode soll das demonstrieren.
#Test-Arrayresult function get-array{ # Lere einfaches Array an $myarray=@(1,"eins",2) write-host "Typ1 = $($result.gettype())" 0..2 | %{write-host $myarray[$_].gettype()} $myarray } $ergebnis=get-array write-host "Typ2 = $($ergebnis.gettype())" 0..2 | %{$ergebnis[$_].gettype()}
Beim Aufruf ist sichtbar, dass in der Funktion noch ein Array vorhanden ist aber das aufrufende Programm ein Array von System.Object
Der Inhalt ist dann wieder die "Objekt-Version" des Basetype.
Weitere Links
- Arrays in PowerShell: anlegen, ändern,
auslesen, sortieren, löschen
https://www.windowspro.de/script/arrays-powershell-anlegen-aendern-auslesen-sortieren-loeschen - Powershell - Pass array from one
function to another
https://community.spiceworks.com/topic/410183-powershell-pass-array-from-one-function-to-another - Arrays in PowerShell: anlegen, ändern,
auslesen, sortieren, löschen
https://www.windowspro.de/script/arrays-powershell-anlegen-aendern-auslesen-sortieren-loeschen