Group-Object: Daten nach Eigenschaften gruppieren mit PowerShell


    Tags:

    Daten gruppieren in PowerShellSQL kann bekannt­lich mit dem Befehl GROUP BY das Ergebnis einer Ab­frage nach den Wer­ten in einer oder mehreren Spalten grup­pieren. Aber auch Power­Shell ist dazu in der Lage, wenn man an Group-Object tabel­larische Daten über­gibt, wie sie von vielen Cmdlets erzeugt werden.

    Zu den wichtigsten Operationen bei der Bear­beitung von Daten gehören das Filtern, Sortieren und eben auch das Gruppieren. Häufig ist es notwendig, diese Maßnahmen zu kombinieren, um ans gewünschte Ziel zu kommen.

    Dateinamen anhand der Erweiterung gruppieren

    So könnte man etwa eine Liste mit Dateinamen, wie sie Get-ChildItem ausgibt, erst nach Extension sortieren und dann nach dieser Eigenschaft gruppieren. Dies hätte den Vorteil, dass Group-Object die Liste aller gefundenen Erweiterungen und die Häufigkeit ihres Vorkommens nicht in beliebiger, sondern in alphabetischer Reihenfolge anzeigt. Filter ließen sich etwa nutzen, um alle Datensätze auszuschließen, die nur einmal vorkommen.

    Um beim ersten Beispiel zu bleiben, ließe sich die Ausgabe von Get-ChildItem folgendermaßen anhand der Namens­erweiterung von Dateien gruppieren:

    Get-ChildItem | Group-Object -Property extension

    Wie erwähnt, würde in diesem Fall die Liste nach keinem Attribut sortiert, also weder nach der Häufigkeit (Attribute "Count" in der Ausgabe von Group-Object) noch nach der Extension ("Name") oder den Dateiobjekten in "Group". Eine Anzeige in alphabetischer Reihenfolge der Extensionen ließe sich so erreichen:

    Get-ChildItem | Sort-Object -Property extension |
    Group-Object -Property extension

    Bei Verwendung von Aliases und dem Verzicht auf den Parameter­namen ließe sich dieser Befehl in Kurzform so schreiben:

    gci | Sort extension | Group extension

    Die Ausgabe würde dann zum Beispiel folgendermaßen aussehen:

    Ausgabe von Get-ChildItem anhand der Extension sortieren und gruppieren

    Möchte man nur die Datei­namens­erweiterungen sehen, die mehr als einmal vorkommen, könnte man diese mit Hilfe von Where-Object (Alias ?) filtern:

    gci | Sort extension | Group extension | ? count -gt 1

    Es ist nicht nur möglich, das Ergebnis eines Cmdlets nach einem Attribut zu gruppieren, vielmehr kann man dafür auch mehrere angeben:

    Get-ChildItem | group extension, attributes

    In diesem Beispiel würden jene Dateien zu Gruppen zusammengefasst, die nicht nur die gleiche Extension, sondern auch die gleichen Datei­attribute besitzen.

    Daten anhand von zwei Eigenschaften gruppieren

    Eventlog auswerten als Anwendung

    Das Gruppieren von Daten ist vor allem dann von Nutzen, wenn sie Einträge in vielfacher Ausfertigung enthalten. Dies trifft beispielsweise auf Log-Dateien zu, wo identische Events immer und immer wieder auftauchen. Dort könnte man eine kompakte Ansicht für die Auswertung von Ereignissen so erhalten:

    Get-WinEvent -ProviderName Microsoft-Windows-Hyper-V-VmSwitch |
    Group-Object Message | Sort Count

    Dieser Aufruf ermittelt alle Log-Einträge für den virtuellen Switch von Hyper-V, gruppiert sie anhand der Nachricht und sortiert diese nach der Häufigkeit ihres Vorkommens.

    Einträge aus dem Eventlog anhand der Nachricht gruppieren

    Wie man bei dieser Ausgabe sieht, wird die Darstellung bei derart umfangreichen Daten sehr schnell unübersichtlich. Dazu trägt vor allem die Spalte Group bei, welche die Datensätze enthält, die man zuvor an Group-Object übergeben hat. Sie liegen als Array vor.

    Array der gruppierten Einträge aufspalten

    Im Fall einer Dateiliste, wie sie obiges Beispiel mit Get-ChildItem liefert, versammeln sich in jeder Gruppe alle Dateiobjekte mit der gleichen Endung, und zwar mit den von gci angezeigten Eigenschaften.

    Eine einfache Möglichkeit, den Inhalt des Arrays bei der Darstellung aufzuspalten, besteht darin, jede Gruppe durch eine Schliefe laufen zu lassen und ihre Elemente einzeln auszugeben:

    Get-ChildItem | Group-Object -Property extension |
    %{"==> $($_.Name) $($_.count)", $_.Group}

    Array mit gruppierten Daten in einer Schleife expandieren

    Wesentlich eleganter ist eine Lösung unter Einsatz von Out-GridView. Dieses Cmdlet zeigt Datensätze in einer Tabelle auf der grafischen Oberfläche an. Ruft man es mit dem Parameter PassThru auf, dann reicht es die markierten Zeilen über die Pipe an weitere Cmdlets durch:

    Get-ChildItem | Group-Object -Property extension |
    Out-GridView -PassThru | Select -ExpandProperty Group

    Hebt man in diesem Beispiel die Extension .xml hervor und klickt auf OK, dann expandiert anschließend der Aufruf von Select den Inhalt der Gruppe.

    Gruppierte Daten in Out-GridView anzeigen und an select-object weiterleiten

    Gruppierte Daten ausblenden

    Oft möchte man aber nur wissen, wie oft eine bestimmte Eigenschaft insgesamt vorkommt, also etwa die Häufigkeit eines Events in der Log-Datei.

    Die zu Gruppen zusammengefassten Nachrichten interessieren dann eigentlich nicht. In diesem Fall ruft man Group-Object mit dem Schalter NoElement auf.

    Transformation zu Hash-Tabelle

    Group-Object unterstützt alternativ den Parameter AsHashTable. Er sorgt dafür, dass die gruppierten Daten als Hash-Tabelle zurückgegeben werden, wobei die Eigenschaft, anhand derer die Gruppierung erfolgt, als Schlüssel dient. In diesem Beispiel wäre dies Extension:

    $ext = Get-ChildItem | Group-Object -Property Extension -AsHashTable -AsString

    Es empfiehlt sich diese Option zusammen mit AsString zu verwenden, um sicherzustellen, dass beispielsweise numerische Daten konvertiert werden.

    Daten gruppieren und als Hash-Tabelle aufbereiten

    Anschließend kann man sich über die Punkt-Notation anzeigen lassen, welche Dateiobjekte zu einer bestimmten Erweiterung gehören:

    $ext.".ps1"

    Keine Kommentare