Zum Hauptinhalt springen

Select-Object

Manche Cmdlets erlauben das Filtern von Objekten bereits beim Aufruf. 

Get-EventLog -LogName Application -EntryType Error -Newest 4

> Index Time          EntryType    Source              InstanceID  Message
> ----- ----          ---------    ------              ----------  -------
> 2684  Mai 26 10:45  Error        Application Error   1000        Name de...
> 2636  Mai 26 00:24  Error        VSS                 13          Volumen...
> 2631  Mai 26 00:24  Error        Application Error   1000        Name de...
> 2486  Mai 25 21:54  Error        Application Error   1000        Name de...

Das Beispiel weist Get-Eventlog an, nur die neuesten 4 Fehler auszugeben. Das ist sehr performant und funktioniert wunderbar. Aber wenn keine passenden Cmdlet-Filter zur Verfügung stehen, muss auf Select-Object und Where-Object zurückgegriffen werden.

Die beiden Befehle sind an SQL angelehnt. Stellen Sie sich dazu die Ausgabe eines Cmdlets als eine Tabelle vor.

Get-Childitem -Path c:\Windows | Out-Gridview

Select object gridview

Abbildung 3 - Die Objekte werden im Gridview tabellarisch dargestellt

Das Select-Kommando in SQL wählt die Spalten aus, die ausgegeben werden sollen. Select-Object wählt die Eigenschaften aus, die Powershell zurückgeben soll. Stellt man die Daten tabellarisch dar, entsprechen die Eigenschaften wieder Spalten (s. Abbildung).

Get-ChildItem -Path C:\Windows | Select-Object -Property Name,Length

Wie in SQL das * der Platzhalter für alle Spalten ist, bezeichnet er bei Select-Object alle Eigenschaften:

Get-ChildItem -Path C:\Windows | Select-Object -Property *

Wie schon im Abschnitt Objekte gesehen, gibt das * deutlich mehr Eigenschaften aus als wenn man nur Get-Childitem alleine aufruft, weil das sogenannte ETS (Extended Type System) dafür sorgt, dass nur die wichtigsten Spalten ausgegeben werden.

Tatsächlich filtert Select-Object nicht die Ausgabe, sondern legt neue Objekte vom Datentyp PSCustomObject mit den im Parameter Property angegebenen Namen an. Danach kopiert es alle Eigenschaften des Original-Objekts, die den gleichen Namen haben wie die Eigenschaften des neuen Objekts. Dies kann auch zu unerwarteten Ergebnissen führen:

Get-Childitem c:\Windows\notepad.exe | Select-object -Property Fullname,Length

FullName                 Lenght
--------                 ------
C:\Windows\notepad.exe

Im Beispiel hat sich ein kleiner Tippfehler eingeschlichen – bei Length sind t und h vertauscht. Select-Object liefert aber keinen Fehler, sondern einfach eine leere Eigenschaft zurück. Das kann man sich auch zunutze machen, um neue Objekte zu erstellen:

$NewUser = 1 | Select-object -Property Name,Surname,Password,Description
$NewUser.Name = 'Holger'
$NewUser.Surname = 'Voges'
$NewUser.Password = 'Passwort'
$NewUser

> Name   Surname Password Description
> ----   ------- -------- -----------
> Holger Voges   Passwort

Im Beispiel wird eine Integer-Wert in den Select-Object gepiped. Im Prinzip kann man jedes beliebige Objekt nehmen. 1 ist einfach schnell zu tippen, und außerdem haben Integer-Zahlen keine Eigenschaften, die in das neu erstellte Objekt übernommen werden könnten. Schöner (und noch kürzer) kann man Objekte aber mit einer Hash-Table erstellen (s.Eigene Objekte erzeugen).

Select-Object hat aber noch weitere Funktionen. So ist es z.B. möglich, nur eine bestimmte Anzahl von Objekten zurück zu geben:

Get-ChildItem -Path C:\Windows | Sort-Object -Property Length -Descending | Select-Object -first 5

In diesem Beispiel sieht man außerdem das Cmdlet Sort-Object in Aktion, dass die Daten zuerst nach der Eigenschaft Length absteigend sortiert. Select-Object gibt mit dem Parameter -First 5 nur die ersten 5 Objekte zurück. Das klappt übrigens auch mit den letzten 5 Objekten:

Get-ChildItem -Path C:\Windows |
   Sort-Object -Property Length -Descending | 
   Select-Object -first 3 -Last 3

> Verzeichnis: C:\Windows

> Mode   LastWriteTime    Length      Name
> ----   -------------    ------      ----
> -a---- 02.01.2020 10:04 2466363143 MEMORY.DMP
> -a---- 23.05.2020 17:26 4483160    explorer.exe
> -a---- 01.05.2019 16:37 2839520    RtlExUpd.dll
> d----- 07.12.2019 10:31            PLA
> d-r--- 23.05.2020 22:28            PrintDialog
> d----- 26.05.2020 11:31            Prefetch

Select-Object kann auch berechnete Eigenschaften erzeugen, anstatt nur Daten aus einem bestehenden Objekt zu übernehmen. Allerdings muss hierfür der Name der neuen Spalte und der zu Berechnung auszuführende Code in einer Hash-Table übergeben werden. Die Hash-Table muss zwei Schlüssel-Wertepaare mit festen Schlüsselnamen beinhalten:

$Dateigroesse = @{
   Name='Größe in KB'
   Expression={ $_.Length/1KB }
}
Get-childitem c:\windows -file | Select-object Name,$Dateigroesse

Name           Größe in KB
----           -----------
bfsvc.exe      76
bootstat.dat   66
comsetup.log   0,744140625
ctfile.rfc     0,1552734375
diagerr.xml    14,8857421875

In der ersten Zeile wird die Hash-Table mit zwei Schlüsseln erstellt: Name für den Namen der berechneten Spalte und Expression für den auszuführenden Code. Der Code wird als Scriptblock angegeben, d.h. von geschweiften Klammern umschlossen.

Die Hash-Table kann man auch kompakter schreiben, indem man die beiden Schlüssel-Wertepaare in der Hashtable durch Semikolon trennt und nicht unter- sondern hintereinander schreibt:

$Dateigroesse = @{ Name='Größe in KB'; Expression={ $_.Length/1KB }} 
Get-childitem c:\windows -file | Select-object Name,$Dateigroesse

Prinzipiell könnte man das Skript noch weiter verkürzen und die Hash-Table direkt im Select-Object angeben, aber das wird dann sehr unübersichtlich:

Get-childitem c:\windows -file |
   Select-object -Property Name,@{ Name='Größe in KB';Expression={ $_.Length/1KB }}