Abgelegt unter: Anleitungen | Tags: DateTime, PowerShell, SCCM, WMI
Während den letzten Tagen habe ich mich etwas intensiver mit der Powershell 2.0 befasst und ich habe mich gefragt, ob und wie ich bestimmte Daten mit Hilfe eines Powershell-Skriptes aus SCCM auslesen kann. So habe ich mir vorgenommen, ein Skript zu schreiben, das mir eine Liste aller vorhanden Clients ausgibt und dabei die Info aus SCCM mitliefert, welcher Benutzer letztmals an diesem Client angemeldet war und wann die letzte Kommunikation des Agent mit dem SCCM-Site Server erfolgte.
Konkret interessierte ich mich also für folgende drei Feldwerte aus den Eigenschaften eines Computerobjektes:
- Name
- Last Logon User Name
- Agent Time (neuester Eintrag)
Der erste Teil des Skriptes war einfacher zu realisieren, als ich dies zuerst vermutete:
$query = New-Object System.Management.ObjectQuery
$query.QueryString = "Select * from SMS_R_System order by Name" $searcher = New-Object`
System.Management.ManagementObjectSearcher($query)
$searcher.Scope.Path = "\\<siteserver>\root\sms\site_<sitecode>"
$result=$searcher.Get()
Ich verwende also die ObjectQuery-Klasse aus dem .NET-Framework, setze die entsprechende Query (die natürlich die gewünschten Felder zielgerichteter auslesen könnte, als mit dem simplen „Select *“), und benutze dann die ManagementObjectSearcher-Klasse, um die Abfrage der gewünschten Informationen basierend auf der definierten Query durchzuführen. Hierzu muss natürlich noch definiert werden, wo genau die Daten gelesen werden sollen, wozu in der vierten Zeile <siteserver>
durch den Namen des entsprechenden SCCM-Siteservers und <sitecode>
durch den dazu passenden Sitecode zu ersetzen ist. Nun noch die Suche gestartet, und schon stehen die gewünschten Daten in $result
.
Bis ich nun die Daten als passend formatierte Tabelle in der Powershell lesen konnte, musste ich deutlich länger suchen (und einem Kollegen auf den Wecker gehen). Schlussendlich führte folgende Codezeile – man beachte die unzähligen Backticks „`
“ für die Fortsetzung der Zeile auf einer neuen Linie – zum Ziel:
$result | `
format-table `
@{label="Computername";`
expression={$_.Name.tolower()};`
width=16},`
@{label="Letzter Benutzer";`
expression={$_.LastLogonUserName};`
width=20},`
@{label="Letzte Agent-Kommunikation";`
expression={(([WMI] "").ConvertToDateTime(`
$($_.AgentTime | Sort-Object | Select-Object -Last 1)`
)).tostring("dd.MM.yyyy HH:mm:ss")};`
width=20}
Der Anfang dieser Zeile – ja es ist eine einzige Zeile! – ist nicht besonders schwierig zu verstehen. Der Inhalt von $result
wird an den Befehl format-table
übergeben, der dann die drei Datenfelder formatiert ausgibt, wobei die Definition eines Datenfeldes jeweils beim @
beginnt.
Bei den beiden ersten Spalten sind keine grossen Besonderheiten zu finden: Ich setze jeweils die gewünschte Spaltenüberschrift (label
) und gebe mit dem jeweiligen Ausdruck (expression
) den aktuellen ($_
) Inhalt des jeweiligen Feldes aus, wobei ich noch die gewünschte Breite der Spalte (width
) festlege. Beim Computernamen verwende ich zusätzlich noch die Funktion tolower()
, da ich eine Liste mit Computernamen in Kleinbuchstaben lesbarer finde.
Die Expression für das Datum der letzten Kommunikation ist jedoch nicht mehr ganz so trivial; Ursache dafür ist die Tatsache, dass alle Zeitstempel im Format „yyyymmddHHMMSS.mmmmmmsUUU“ geliefert werden. Ich benutze deshalb die Funktion ConvertToDateTime
, um daraus eine „brauchbare“ Zeit zu machen, die dann mit tostring("dd.MM.yyyy HH:mm:ss")
in die gewünschte Darstellung umgewandelt wird.
Bleibt also noch die Zeile „$($_.AgentTime | Sort-Object | Select-Object -Last 1)
“ zu erläutern: In SCCM ist AgentTime ein mehrwertiges Feld, d.h. es werden mehrere Zeitstempel gespeichert, wann ein Client mit dem Server gesprochen hat. Die gespeicherten Werte werden deshalb per Pipe an den Sortierer geschickt und dann der letzte (d.h. der neueste) Wert ausgewählt.
Klar: Dieses Skript ist nichts besonderes; es gibt in SCCM vordefinierte Reports, welche dieselbe Informationen (und noch mehr dazu) mit Hilfe weniger Mausklicks liefern können. Doch dieses Skript zeigt exemplarisch, wie so eine Query in Powershell realisiert werden könnte, womit diese auch als Basis für komplexere Abfragen dienen könnte.
Komplette Skriptdatei: computersystems.ps1 (zip)