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

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 }}