Behandelte Themen unter "WMI"
0.
WMI-Theorie
1.1Namespaces
Beispiel 1: Namespaces auf einem Rechner ermitteln
Beispiel 2: Namespace "root/MicrosoftDNS" anstelle des DefaultNameSpaces "root/cimV2" verwenden
1.2Provider
Beispiel 1: Ermitteln der Provider des Namespaces root/cimV2
1.3Klassen / Eigenschaften / Methoden/Objekte / Managed Resources
Beispiel 1: Ermitteln der Klassen des Namespaces root/cimV2
Beispiel 2: Ermitteln von Eigenschaften und Methoden eines WMI-Objekts (Instanz)
Beispiel 3: Ermitteln von Eigenschaften und Methoden einer WMI-Klasse mit einer WMI-SchemaqueryStandard WMI-Abfragen
2.1DataQueries
Beispiel 1: Alle Informationen des lokalen BIOS ermitteln
Beispiel 2: Abfrage der aktuellen Temperatur des Rechners mit einer Klasse aus dem "root/wmi" Namespace
Beispiel 3: Erforschen des Namespaces "root/MicrosoftDNS" mit WBEMTest
2.2WQL - WMI Query Language
Beispiel 1: WMI-query mit Where Klausel
Beispiel 2: WMI-query mit gefilterten Eigenschaften + Keyword LIKE in der Where Klausel
Beispiel 3: IstGleich-Bedingung in WhereKlausel
Beispiel 4: "Ist nicht Null"-Bedingung in WhereKlausel
2.3WMI-Abfragen optimieren
2.4WMI-Methoden
Beispiel 1: Anzeigen der Methoden der Klasse Win32_Service
Beispiel 2: Methode StopService() aus win32_Service
Beispiel 3: Methode StartService() aus win32_Service
Beispiel 4: Starten und Stoppen eines Dienstes mit StartService() bzw. StopService() aus win32_Service
Beispiel 5: Hinzufügen eines Clients in eine AD-Domäne und Reboot
Beispiel 6: Entfernen eines Clients aus einer AD-Domäne
2.5EventQueries
Beispiel 1: Alle von einer WMI-Klasse erzeugten CreationEvents überwachen und eine Aktion ausführen
Beispiel 2: Von einer WMI-Klasse erzeugten und gefilterten CreationEvents überwachen und die Ergebnisse in ein Event schreiben
Beispiel 3a: Anzeige aller registrierten Event-Subscriber
Beispiel 3b: Löschen aller registrierten Event-Subscriber
2.6SchemaQueries
2.6.1SchemaQueries mit Powershellsyntax (cmdlet Get-WMIObject und Systemklasse "Meta_Class")
Beispiel 1: Alle Klassen des Namespaces “root/wmi”
Beispiel 2a: Beschränkung der Ausgabe auf eine Klasse mit Hilfe der Eigenschaft __Class von meta_class
Beispiel 2b: Beschränkung der Ausgabe auf eine Klasse mit Hilfe der Eigenschaft __This ISA von meta_class
Beispiel 3: Alle TOP-Klassen des Namespaces "root/cimV2"
Beispiel 4: eine Instanz einer Klasse selbst erstellen und darauf eine (statische) Methode anwenden
2.6.2SchemaQueries in .Net Syntax ( [System.Management.ManagementClass] bzw. dem TypeAccelearator [wmiClass] )
Beispiel 1: eine Instanz einer Klasse selbst erstellen und darauf eine (statische) Methode anwenden
Beispiel 2: Eine Objektinstanz erstellen und die Eigenschaften der Instanz abfragen
2.7Associators of
2.7.1Beispiele zum "Associators of" Kommando
Beispiel 1a: Welches Verzeichnis liegt hinter dem Sharenamen "temp" und welche Eigenschaften hat das Share
Beispiel 1b: Welche Shares liegen auf einem Verzeichnis
Beispiel 2: Welche User greifen von welchen Computern auf ein Share zu
Beispiel 3: Auslesen aller AD-Gruppen
Beispiel 4: Ermitteln aller an einem Computer angemeldeten Useraccounts (Domaincontroller oder Client)
2.7.2Einsatz des WMI Object Browsers Syntaxvarianten von WMI in Powershell
3.1WMI-Befehle
3.1.1TypeAcceleratoren/ TypeShortcuts
3.1.2cmdlets
3.2WMI Syntax (Instanzbasiert)
3.2.1Beispiele: Instanz eines existierenden Shares erstellen
Beispiele 1: cmdlet "Get-WmiMethod" (gwmi)
Beispiele 2: TypeAccelerator [wmi]
Beispiel 3: TypeAccelerator [wmiSearcher]
3.2.2Methoden auf eine existierende Instanz anwenden
Beispiel 1: Setzen einer ShareBeschreibung mit cmdlet "Get-WmiMethod"
Beispiel 2: Setzen einer ShareBeschreibung mit cmdlet "Invoke-WmiMethod"
Beispiel 3: Setzen einer ShareBeschreibung mit dem TypeAccelerator [wmi]
3.3WMI Syntax (statisch)
3.3.1Instanz einer Klasse erstellen (=SchemaQuery)
3.3.2Ein neues Objekt aus einer Klasse erstellen (statische Methode)
Beispiel 1: Share Erstellen mit Get-WmiMethod (gwmi)
Beispiel 2: Share Erstellen mit Invoke-WmiMethod (iwmi)
Beispiel 3: Share Erstellen mit TypeAccelerator [wmiClass]WMI-Praxisbeispiele
4.1FileSystem
Beispiel 1: Defrag mit Win32_Volume und Win32_DefragAnalysis
4.2Informationen zum Betriebssystem
Beispiel 1a: Mit Win32_Systemdriver alle Treiber mit Versionsnummer auslesen
Beispiel 1b: Treiber in HTML-Datei schreiben mit WMIC
Beispiel 2a: Feststellen, ob der Host virtuell oder physikalisch installiert ist
Beispiel 2b: Feststellen, ob ein Host virtuell oder physikalisch installiert ist und Angabe des VirtualisierersWenn 's mal hakt weitere interessante Links (|-> 10.03.2011)
Danke an phoenixcp, cybquest, Dr.Melzer und olc fürs ReviewLesen dieses Kapitels!
*********************************************************************************************************************
0 Einleitung
WMI (Windows Management Instrumentation) bietet Skriptern und Programmierern eine einfache und konsistente Schnittstelle, um eine riesige Menge an Informationen von lokalen oder auch von entfernten Rechnern abzufragen. Wenn man mit WMI noch nicht gearbeitet hat, wird man überrascht sein, wie einfach sich Informationen über sogenannte Managed Objects von einem einzelnen oder auch von vielen hundert Rechnern einsammeln und verändern lassen. Solche Managed Objects können zum Beispiel BIOS, Betriebssystem, Netzwerkkarten oder Laufwerke sein. Alleine dafür lohnt es sich einen Blick auf WMI zu werfen, der unter diesem Ziel sicher nicht allzuviel Zeit und Mühe erfordern wird.
Will man aber WMI verstehen und tiefer ausreizen, so muss man etwas mehr Zeit investieren, um neben den üblichen Standard-Datenqueries auch Eventqueries und Schemaqueries zu verstehen.
Dann sollte man sich auch die Zeit nehmen, um immer wieder anfallende Begriffe wie CIM, WBEM, Provider, Klassen einordnen zu können.
Und letztlich gibt es einige mächtige WMI-Tools, die im Werkzeugkasten eines Skripters bereit liegen sollten.
1 WMI Theorie
Eine Einführung in die WMI-Architektur findet man in diesem Artikel
Dieses theoretische WMI Architekturkapitel zu lesen, lohnt sich zum besseren Verständnis von WMI auf jeden Fall.
WMI ist die Microsofts Umsetzung von WBEM (Web Based Enterprise Management), welches wiederum von der DMTF (Desktop Managed Task Force) definiert wird. Wer richtig Hardcore einsteigen möchte, findet auf der Website der
1.1 Namespaces
Namespaces sind die größten Einheiten, in denen Informationen der riesigen WMI-Welt zusammengefasst sind. Beim Programmieren mit WMI muss man aufpassen und wissen, in welchem Namespace sich ein Provider oder eine Klasse befindet. Ohne die Angabe des korrekten Namespaces funktioniert der Aufruf einer Klasse nicht oder man arbeitet mit einer gleichnamigen Klasse eines anderen Namespaces. In vielen Fällen ist der definierte DefaultNamespace mehr oder weniger zufällig gerade der richtige, so dass ein Fehlen des Namespace sich nicht bemerkbar macht.
Der Default NameSpace ist in der Registry hinterlegt unter
Registry-Key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\Scripting
wo normalerweise ein REG_SZ Eintrag "Default Namespace" mit dem Wert "root\cimV2" existiert. Der Namespace root\cimV2 ist einer der umfangreichsten und enthält unter anderem den Win32_Standardprovider (siehe unten
Um Namespaces selbst zu erforschen, gibt es eine Reihe von Tools, von denen ich hier aber nur kurz einge aufzählen und erst später im Laufe des Kapitels genauer beschreiben will:
a) Das windowseigene Tool wbemtest.exe ist nicht nicht allzu komfortabel, aber mit etwas probieren bekommt man viele Informationen über einen Namespace
b) Der WMI-Explorer
c) Eine ganze Sammlung mit den WMI-Tools:
Beispiel 1: Namespaces auf einem Rechner ermitteln
Auch aus einem Powershellskript selbst heraus, lassen sich Namespaces auslesen.
Die Klasse __NameSpace ist eine sogenannte Systemklasse, erkennbar an den "__" zu Beginn des Klassennamens.
$computer="."
$Namespace="root"
$NS=Get-WmiObject __NameSpace -Computer $Computer -NameSpace $NameSpace |select name
$NS | foreach {
"$namespace"+'\'+ $_.name
}
#Ausgabe
root\ServiceModel
root\SECURITY
root\CCM
root\RSOP
root\Cli
root\aspnet
root\SecurityCenter
root\WMI
root\CIMV2
root\Policy
root\SmsDm
root\Microsoft
root\DEFAULT
root\directory
root\subscription
root\nap
#wobei es noch weitere, tiefer verschachtelte Namespaces gibt, die aber -denke ich- nicht so interessant sind
Je nachdem, welche Software auf einem Rechner installiert ist, können die enthaltenen Namespaces unterschiedlich sein. So besitzt ein Domaincontroller üblicherweise zusätzlich diese Namespaces
root\MicrosoftActiveDirectory
root\MicrosoftDNS
will man auf die DNS-Datenbank mittels WMI zugreifen, so muss der Namespace "root\MicrosoftDNS", der wahrscheinlich nie der in der Registry eingetragene DefaultNamespace sein wird, explizit angegeben werden.
Beispiel 2: Namespace "root/MicrosoftDNS" anstelle des DefaultNameSpaces "root/cimV2" verwenden
Die DNS-Klassen befinden sich nicht im StandardNamespace root/cimV2, daher muss der Namespace explizit im Skript angegeben werden.
$WinNS="root/MicrosoftDNS"
get-wmiobject -class MicrosoftDNS_Server -namespace $WinNS -computer dc1
#Ausgabe gekürzt
DefaultAgingState : False
DsTombstoneInterval : 1209600
EDnsCacheTimeout : 900
EnableDirectoryPartitions : True
Interessant ist weiterhin, dass man auf Namespaces Securitydescriptoren setzen und anzeigen lassen kann.
In der MMC dazu das SnapIn "WMI-Steuerung" hinzufügen und auf den lokalen bzw. einen Remoterechner verbinden.
Um WMI lokal oder remote ausführen zu können, benötigt man die Rechte eines lokalen Administrators.

1.2 Provider
Unter den Namespaces sind die Provider eingehängt. Provider bilden die Schnittstelle zwischen den sogenannten "managed resources" und dem WMI-Service. Managed Resources sind all die schönen Dinge, die man über WMI managen kann, wenn denn ein Provider existiert.
Beispiel 1: Ermitteln der Provider des Namespaces root/cimV2
$computer="."
$PV=Get-WmiObject __Win32Provider -Computer $Computer -NameSpace "root\cimv2"
$PV | sort | foreach {
$_.name
}
#Ausgabe stark gekürzt
CIMWin32
Cimwin32A
HiPerfCooker_v1
Win32_WIN32_TERMINAL_Prov
Win32_WIN32_TERMINALSERVICE_Prov
Win32_WIN32_TERMINALSERVICESETTING_Prov
WMIPingProvider
Der CIMWin32-Provider ist beispielsweise der Win32_Provider, der den Zugriff auf Computer, Disks, Files, FileSysteme, Netzwerkkarten, Drucker, Prozesse , Freigaben und vieles mehr bereitstellt.
Der HiPerfCooker stellt dagegen den Zugriff auf Performancedaten bereit.
In der Powershell selbst hat der Begriff "Provider" die Bedeutung von Laufwerk, wobei ein Laufwerk neben den üblichen logischen Laufwerken C:\ oder D:\. ein Registryast, das Activedirectory, Aliase und weitere sein können_ Alle PowershellProvider kann man mit "get-psdrive" ermitteln und darauf mit "Set-Location <Providernamen>:" zugreifen.
1.3 Zusammenfassung Klassen/ Eigenschaften/ Methoden/ Objekte/ Managed Resources/ Provider / Namespaces
Wer sich unter Klassen und den weiteren Begriffen immer noch nicht so richtig etwas vorstellen kann, mich auf eine kurze Reise in unsere Kindheit am Sandkasten begleiten und danach vielleicht nochmal den in Kapitel 1 erwähnten MSDN Artikel ansehen:
In unserer Kindheit besaß sicher jeder von uns viele verschiedene bunte Plastikförmchen. Aus diesen Förmchen konnten wir je nach ihrer Form, Höhe, Länge, Volumen verschiedene Sandfiguren (Autos, Häuschen, Brezen) backen. Dazu mussten wir die Förmchen mit Sand füllen, glattstreichen, mit Schwung umdrehen und auf einen Stein drücken.
Mit den so erstellten Sandfiguren haben wir dann verschiedene Dinge angestellt, wie ein Loch hineingestochen, zerstört, ein zweite Figur daraufgesetzt, Wasser draufgegossen...
Auch wenn wir es damals noch nicht wussten: Wir haben schon objektorientiert gehandelt!
Zuerstmal haben wir, bevor wir zum Sandkasten aufgebrochen sind, uns über die passenden Spielsachen Gedanken gemacht. Wir haben -übertragen gesprochen- die passenden Namespaces ausgewählt: Namespace1=Sandspielzeug und Namespace2=Ballspiele wurden in eine grosse Tüte gepackt, während wir Namespace3=Bilderbücher zu Hause ließen und Namespace4=Puppen als Jungs gar nicht installiert hatten.
Am Sandkasten angekommen haben wir aus Namespace1 dasjenige Förmchen (=Klasse) ausgewählt, das uns aufgrund seiner Eigenschaften und Methoden am geeignetesten schien, unsere selbstgestellte Aufgabe (=Kuchenbacken) zu erfüllen.
Für das Backen eines neuen Kuchens (=Instanz/ Objekt) benötigten wir andere Methoden (die sogenannten statischen Methoden), wie für das Umgehen mit den fertigen Kuchen (die sogenannten instanzbasierten Methoden).
Wir haben sicher nicht nur einen Kuchen (=Instanz/ Objekt) gebacken, sondern vielleicht 3 oder 10 oder noch mehr Objekte nacheinander aus dem Förmchen herausgeholt.
Die erschaffenen Objekte sahen zwar alle gleich aus, waren aber untereinancer völlig unabhängig. Wir konnten einen der zehn Sandkuchen zerstören, die anderen neun existierten erstmal weiter.
Das Förmchen oder die Klasse hätte auch nach einhundert Kuchen (=Instanzen/ Objekte) den einhundert-und-ersten Kuchen wieder genauso ausgegeben wie den ersten.
Sowohl das Erstellen der KuchenObjekte mit den Förmchen, als auch der Umgang mit den erstellten KuchenObjekten selbst haben uns den Spaß am Sandkasten gebracht. Jeder Vorgang für sich alleine wäre viel langweiliger zu spielen gewesen.
Wenn wir dann genügend Kuchenobjekte erstellt und verschiedene Methoden darauf angewendet hatten, interessierten wir uns vielleicht sogar für die Förmchen selbst und legten alle gelben Förmchen auf einen Haufen, die roten auf einen anderen. Wir interessierten uns für die Eigenschaften der Klasse selbst (=Schema). Solche Eigenschaften eines Förmchen (Klasse) waren möglicherweise Farbe, Volumen, Material, Hersteller. Einige dieser Eigenschaften, wie das Volumen wirkten sich auf die die erstellten KuchenObjekte aus, andere wie die Farbe des Förmchens sicher nicht.
Beim Sortieren nach Gelb und Rot haben wir eine sogenannte Schemaquery auf die Farbe der Förmchen gemacht
Zurück ins Jetzt:
Auch eine WMI-Klasse wie "Laufwerk" alleine bringt beim Skripten wenig Erhellendes zu einem bestimmten Laufwerk, welches in unserem Recher arbeitet. Erst wenn man die Klasse auf unser Laufwerk C:\ (=managed resource) anwendet, kann man interessante Eigenschaften des jetzt vorliegenden Objekts abfragen (Speicherplatz, Hersteller) oder Methoden anwenden (Datenträgerbezeichnung verändern oder formatieren).
Versucht man die eben noch so hilfreiche Klasse Laufwerk dagegen auf einen Drucker (=managed resource) anzuwenden, so passt die Laufwerksklasse überhaupt nicht zum Drucker und es wird kein Objekt erstellt, mit dem man arbeiten könnte.
Und man kann beispielsweise eine WMI-Klasse "Share" überhaupt nicht anwenden, solange noch keine Share (=Instanz/ Objekt) existiert. Shares können wir erstellen, indem wir die statische Methode "create" der Klasse Win32_Share anwenden, die uns die gewünschten ShareObjekte erstellt.
Am Ende dieses Abschnitts will ich nur ein paar ganz kurze Beispiele zu den verwendeten Begriffen zeigen. In den darauf folgenden Abschnitten folgt zu jeder Analogie eine ausführliche Erklärung
Beispiel 1: Ermitteln der Klassen des Namespaces root/cimV2
Get-WMIObject -list -namespace "root/cimV2"
#gleichwertig mit einer Schemaquery siehe Abschnitt 2.6 "
#Get-WMIObject –query "select * From Meta_Class" -namespace "root\cimV2"
#Ausgabe gekürzt
Win32_GroupInDomain {} {GroupComponent, PartComponent}
Win32_COMApplicationClasses {} {GroupComponent, PartComponent}
Win32_ClassicCOMApplicationClasses {} {GroupComponent, PartComponent}
CIM_DirectoryContainsFile {} {GroupComponent, PartComponent}
Win32_UserInDomain {} {GroupComponent, PartComponent}
CIM_SoftwareFeatureSoftwareElements {} {GroupComponent, PartComponent}
Hier prallen eigentlich zwei unterschiedliche Welten aufeinander, auf der einen Seite die WMI-Klassen und auf der anderen Seite die Powershellwelt, die auf .Net-Klassen basiert. Die von dem cmdlet Get-WmiObject an die Powershell gelieferten WMI-Objekte lassen sich aber ebenso weiterverarbeiten, als ob es von Haus aus Powershell/ .Net Objekte wären. Der Übergang funktioniert absolut problemlos, was auch im folgenden zu sehen ist, wenn wir aus den Klassen die zugehörigen Eigenschaften und Methoden herauslesen.
Beispiel 2: Ermitteln von Eigenschaften und Methoden eines WMI-Objekts (Instanz)
die 3 Kommandos liefern jeweils eine andere Darstellung derselben Informationen
Get-WMIObject Win32_Bios | Select *
Get-WMIObject Win32_Bios | Get-Member
(Get-WMIObject Win32_Bios).Properties | select *
Am besten alle Varianten selbst mal durchprobieren
Beispiel 3: Ermitteln von Eigenschaften und Methoden einer WMI-Klasse mit einer WMI-Schemaquery (siehe auch Abschnitt 2.6)
hier wird mit der Systemklasse Meta_Class und deren Eigenschaft __Class eine Query auf die Klasse erstellt, nicht auf eine Instanz oder ein Objekt
$namespace="root/cimV2"
$query=”Select * From Meta_Class Where __Class = 'Win32_bios'"
$class=Get-WMIObject –query $query -namespace $namespace
$class.properties | select name
#Ausgabe gekürzt
# identisch zu (Get-WMIObject Win32_Bios).Properties | select name
Name
----
BiosCharacteristics
BIOSVersion
BuildNumber
Caption
CodeSet
CurrentLanguage
2 WMI-Abfragen
In Kapitel 1 ging es sehr theoretisch zu, dafür bietet Kapitel 2 jetzt viele praktische Informationen.
2.1 DataQueries
Eine DataQuery ist eine Abfrage, wie sie wahrscheinlich die meisten Skripter schon oft ausgeführt haben. Man hat eine managed resource, kennt hoffentlich die passende Klasse dazu und kann damit (entsprechende Berechtigungen vorausgesetzt) Informationen von einem oder mehreren Rechnern über die gewünschte Resource abfragen.
Beispiel 1: Alle Informationen des lokalen BIOS ermitteln
In der MSDN sucht man nach der passenden Klasse. Alle WMI-Win32 Klassen (die meistens bei der Abfrage von managed resources gebraucht werden) findet man gesammelt unter
Neben den dort beschriebenen Eigenschaften und Methoden sind zwei Dinge generell zu beachten:
a) am Ende der Beschreibung findet man den Namespace wie "root/cimV2"
b) am Ende der Beschreibung findet man die unterstützten Betriebssysteme der Klasse wie "Minimum Windows 2000"
zu a) lautet der Namespace root/cimV2, so handelt es sich um den normalerweise in der Registry hinterlegten DefaultNamespace (siehe
zu b) manch schöne Eigenschaft ist leider erst ab aktuellen OS-Versionen verfügbar. Daher hier nachsehen, wenn bestimmte Eigenschaften/ Methoden partout nicht funktionieren wollen.
Für ein erstes Ergebnis reicht es jetzt aus die Powershell zu öffnen und folgende Zeile abzuschicken
Get-WmiObject Win32_Bios |format-list * -Namespace "root/cimV2"
#gwmi Win32_Bios |fl * # mit den Aliasen gwmi und fl gehts noch etwas schneller
#Ausgabe gekürzt
Description : Ver 1.00PARTTBLX
Manufacturer : LENOVO
OtherTargetOS :
PrimaryBIOS : True
ReleaseDate : 20090422000000.000000+000
SerialNumber : R8PAZR1
SMBIOSBIOSVersion : 6FET66WW (2.16 )
Anstelle von Win32_Bios kann man natürlich viele andere Klassen aus dem MSDN-Link oben einsetzen.
Unter VBS war es noch etwas mühsam, eine Verbindung zum WMI-Service herzustellen, bevor man die WMI-Abfrage abschicken konnte. Unter Powershell hat man nur noch einen simplen Einzeiler.
Beispiel 2: Abfrage der aktuellen Temperatur des Rechners mit einer Klasse aus dem "root/wmi" Namespace
$NameSpace="root/wmi"
$Query="select * from MSAcpi_ThermalZoneTemperature"
get-wmiobject -query $Query -namespace $NameSpace
#Ausgabe gekürzt
CriticalTripPoint : 3732
CurrentTemperature : 3122
InstanceName : ACPI\ThermalZone\THM1_0
PassiveTripPoint : 3687
Reserved : 3
SamplingPeriod : 600
ThermalConstant1 : 5
ThermalConstant2 : 4
ThermalStamp : 6
Die Bedeutungen der Eigenschaften sowie die Einheiten der Werte findet man unter:
einen kleinen Auszug von dieser Seite:
CriticalTripPoint | |
| Datentyp: integer/usint32 |
| Temperature (in tenths of degrees Kelvin) at which the OS must shutdown the system (ie, critical temperature) |
CurrentTemperature | |
| Datentyp: integer/usint32 |
| Temperature at thermal zone in tenths of degrees Kelvin |
PassiveTripPoint | |
| Datentyp: integer/usint32 |
| Temperature (in tenths of degrees Kelvin) at which the OS must activate CPU throttling (ie, enable passive cooling) |
mit der Einheit Kelvin (K) wird üblicherweise in der Physik gerechnet. 0 K entsprechen dem absoluten Nullpunkt, 273.2 K entsprechen 0°Celsius
für das Beispiel meines Notebooks oben bedeutet das:
- die aktuelle CPU-Temperatur meines Notebooks beträgt 312,2(K), was (312,2-273,2)=39°Celsius entspricht
- bei einer Temperatur von 368,7 (K), was (368,7-273,2)=95,5°Celsius entspricht, wird Windows die CPU-Leistung reduzieren
- bei einer Temperatur von 373,2 (K), was (373,2-273,2)=100°Celsius entspricht, wird Windows das System herunterfahren
Beispiel 3: Erforschen des Namespaces "root/MicrosoftDNS" mit WBEMTest
Oft bietet selbst das MSDN für viele Namespaces nicht alle notwendigen Informationen. Dann sind die oben schon erwähnten Tools (WMI-Explorer, WMI-Tools, wbemtest) goldrichtig, um Namespaces und Klassen selbst zu erforschen.

2.2 WQL - WMI Query Language
WQL ist eine auf WMI-zugeschnittene, von SQL und CQL abgeleitete Sprache, mit der in WMI Abfragen definiert werden. Im Wesentlichen geht es darum, welche Eigenschaften (select * oder select manufacturer,releasedate) man von nach bestimmten Kriterien ausgewählten Instancen (where name='Microsoft') zurückhaben will.
Eine vollständige Tabelle mit den möglichen WQL-Keywords findet man unter
Ich habe einen Auszug dieser Tabelle mit den meisten im folgenden behandelten Keywords erstellt:
WQL keyword | Meaning |
AND | Combines two Boolean expressions, and returns TRUE when both expressions are TRUE. |
FALSE | Boolean operator that evaluates to 0 (zero). |
FROM | Specifies the class that contains the properties listed in a SELECT statement. Windows Management Instrumentation (WMI) supports data queries from only one class at a time. |
IS / IS NOT | Comparison operator used with NOT and NULL. The syntax for this statement is the following: |
LIKE | Operator that determines whether or not a given character string matches a specified pattern. |
NULL | Indicates an object does not have an explicitly assigned value. NULL is not equivalent to zero (0) or blank. |
OR | Combines two conditions. When more than one logical operator is used in a statement, the OR operators are evaluated after the AND operators |
SELECT | Specifies the properties that are used in a query. |
TRUE | Boolean operator that evaluates to -1 (minus one). |
Where | Narrows the scope of a data, event, or schema query. |
Beispiel 1: WMI-query mit Where Klausel
Dieses Beispiel gibt alle Eigenschaften der WMI-Klasse win32_service zurück, aber nur wenn der Service den Status "OK" trägt und sich im Zustand (state) "Stopped" befindet
$query = "select * from win32_service where status='OK' and state='stopped'"
Get-WMIObject -query $query| select name, status,state
#Ausgabe gekürzt
name status state
---- ------ -----
ADMonitor OK Stopped
Alerter OK Stopped
ALG OK Stopped
AppMgmt OK Stopped
Beispiel 2: WMI-query mit gefilterten Eigenschaften + Keyword LIKE in der Where Klausel
Hier werden nur wenige Eigenschaften einer Klasse (name, PowerManagementSupported) abgefragt und nur zurückgeben, wenn im Namen des Netzwerkadapters das Wort "Intel" vorkommt. (Der Like Operator ist unter Windows 2000 nicht verfügbar!)
$query = "select name,PowerManagementSupported from win32_networkadapter where name Like '%intel%'"
gwmi -query $query | select name,PowerManagementSupported
name PowerManagementSupported
---- ------------------------
Intel(R) 82567LM Gigabit Network Connection False
Intel(R) WiFi Link 5100 AGN False
Die folgende Tabelle enthält die Metazeichen, die man zusammen mit dem Keyword LIKE verwenden kann
Character | Description |
[ ] | Any one character within the specified range ([a=f]) or set ([abcdef]). |
^ | Any one character not within the range ([^a=f]) or set ([^abcdef].) |
% | Any string of 0 (zero) or more characters. The following example finds all instances where "Win" is found anywhere in the class name: SELECT * FROM meta_class WHERE __Class LIKE "%Win%" |
_ (underscore) | Any one character. Any literal underscore used in the query string must be escaped by placing it inside [] (square brackets). |
Innerhalb der Where-Operators können mit folgenden Vergleichsoperatoren Bedingungen formuliert werden. Zu beachten ist der Unterschied zwischen
"IS" und "="
"IS NOT" und "!="
Folgende VergleichsOperatoren stellt WQL bereit
Operator | Description |
= | Equal to |
< | Less than |
> | Greater than |
<= | Less than or equal to |
>= | Greater than or equal to |
!= or <> | Not equal to |
Beispiel 3: IstGleich-Bedingung in WhereKlausel
$query="SELECT * FROM Win32_LogicalDisk WHERE DriveType = 5"
get-wmiobject -query "SELECT * FROM Win32_LogicalDisk WHERE DriveType = 5" #IS 5 wäre falsche Syntax
#Ausgabe
DeviceID : D:
DriveType : 5
ProviderName :
FreeSpace : 0
Size : 72574976
VolumeName : SCRIPT_WMI
Dazu kommen noch der IS bzw. der IS NOT Operator. Diese beiden Operatoren müssen eingesetzt werden, wenn eine "NULL-condition" abgefragt wird. d.h. ob eine Eigenschaft überhaupt einen Wert hat. NULL ist nicht gleich 0 !!
Beispiel 4: "Ist nicht Null"-Bedingung in WhereKlausel
$query="select * from win32_networkadapter where MACAddress is not null" #!= geht nicht
get-wmiobject -query $query | select MACAddress,DeviceID
#Ausgabe
MACAddress DeviceID
---------- --------
00:24:7E:6F:09:63 1
00:1E:65:CA:E1:84 2
50:50:54:50:30:30 6
33:50:6F:45:30:30 7
02:80:37:EC:02:00 10
2.3 WMI-Abfragen optimieren
Meistens findet man WMI Beispiele, die vielleicht der Übersichtlichkeit halber einfach alle Informationen von der managed resource abfragen. (Select * From, Win32_class). Setzt man WMI in produktiven Skripten (evtl. als LoginSkript) ein, sollte man den dadurch verursachten erhöhten Resourcenverbrauch (CPU oder die bei Remoteabfragen übertragene Datenmenge) bedenken. Man sollte Anfragen auf die tatsächlich benötigte Elemente beschränken, wie an der folgenden Tabelle ersichtlich ist.
Query | Bytes Returned |
|---|---|
objSWbemServices.InstancesOf("Win32_Service") | 157,398 |
objSWbemServices.ExecQuery("SELECT * FROM Win32_Service") | 156,222 |
objSWbemServices.ExecQuery("SELECT Name FROM Win32_Service") | 86,294 |
objSWbemServices.ExecQuery("SELECT StartMode FROM Win32_Service") | 88,116 |
objSWbemServices.ExecQuery _ ("SELECT StartMode FROM Win32_Service WHERE State=‘Running’") | 52,546 |
objSWbemServices.ExecQuery _ ("SELECT StartMode, State FROM Win32_Service WHERE State=‘Running’") | 56,314 |
objSWbemServices.ExecQuery _ ("SELECT * FROM Win32_Service WHERE Name=‘WinMgmt’") | 27,852 |
Da man ja bekanntlich keiner Statistik trauen soll, die man nicht selbst gefälscht hat, habe ich versucht diese Zahlen zu verifizieren. Ich habe auf meinem virtuellen Win7-Client folgende Abfragen gegen den virtuellen Domaincontroller DC1 ausführen lassen (IP4!) und die Zeiten sowie den Netztraffic mittels Wireshark gemessen.
Beispiel 1: Vergleich "select *" mit "select name, state"
function getService
{
param($query)
$services=gwmi -query $query -computer "dc1"
$services| foreach{
if ($_.name -eq "DNS"){
"$($_.name),$($_.state)"
}
}
}
$query1="select * from win32_service"
$query2="select name,state from win32_service where state='stopped'"
"Ergebnis in Millisekunden für $query1: select * from win32_service"
(measure-command {getservice($query1)}).TotalMilliseconds
"`nErgebnis in Millisekunden für $query2: select name,state from win32_service where state='stopped'"
(measure-command {getservice($query2)}).TotalMilliseconds
#Ergebnis
Ergebnis in Millisekunden für select * from win32_service
463,3438
Ergebnis in Millisekunden für select name,state from win32_service where state='stopped'
128,637
Nach 5 Versuchen habe ich diese Tabelle erstellen können.
| Milliseconds | Bytes |
Query1 | 460 ± 50 | 240,000 ± 10,000 |
Query2 | 160 ± 50 | 65,000 ± 10,000 |
Die Zeit in Millisekunden hat relativ stark geschwankt, unter anderem abhängig davon, ob man die Query einmal oder mehrfach schnell hintereinander ausgeführt hat. Die gemessenen Kilobytes waren dagegen recht stabil.
Zur Netzwerkmessung habe ich Wireshark benutzt. Da auf dem TestNetz sonst keine anderen Rechner Traffic verursachten, konnte ich die übertragenen Kilobytes leicht messen. Wireshark -> Menu Statistics -> Summary -> Bytes.
Man darf die absoluten Zahlen aus dem MSDN nicht mit meinen gewonnenen Zahlen vergleichen, dazu sind die Unterschiede der Messmethoden und der Randbedigungen wie die verwendeten Betriebssysteme oder das Netzwerk viel zu gross. Aber tendenziell kann ich die Zahlen der Technet nachvollziehen.
2.4 WMI-Methoden
Viele WMI-Klassen bringen auch recht interessante Methoden mit.
Beispiel 1 : Anzeigen der Methoden der Klasse Win32_Service
Get-WMIObject Win32_service | gm -membertype Method
#Ausgabe gekürzt
TypeName: System.Management.ManagementObject#root\cimv2\Win32_Service
Name MemberType Definition
---- ---------- ----------
PauseService Method System.Management.ManagementBaseObject PauseService()
ResumeService Method System.Management.ManagementBaseObject ResumeService()
StartService Method System.Management.ManagementBaseObject StartService()
StopService Method System.Management.ManagementBaseObject StopService()
Beispiel 2: Stoppen eines Dienstes mit get-wmiobject (gwmi)
$srv=get-wmiobject -query "select * from win32_service where name = 'spooler'"
$srv.stopservice()
# identisch mit
#$srv.InvokeMethod("StopService",$null)
"Returnvalue=" + $returncode.Returnvalue
#Ausgabe
Returnvalue=0
Anmerkung: Der Return Value liefert wertvolle Hinweise, ob die Methode fehlerfrei (Return Value = 0) ausgeführt wurde, oder warum Fehler auftraten. Return Value = 2 bedeutet "Access Denied".
Nachzuschlagen kann man die Returnwerte der StopService Methode unter
Beispiel 3: Starten eines Dienstes mit get-wmiobject (gwmi)
$srv=get-wmiobject -query "select * from win32_service where name = 'spooler'"
$srv.startservice()
# identisch mit
#$srv.InvokeMethod("StartService", $null)
"Returnvalue=" + $returncode.Returnvalue
#Ausgabe
Returnvalue=0
Nachzuschlagen kann man die Returnwerte der StartService Methode unter
Beispiel 4: Starten und Stoppen eines Dienstes mit invoke-wmimethod (iwmi)
Etwas direkter erlaubt das mit Powershell 2.0 hinzugekommene cmdlet invoke-wmimethod den Aufruf einer Methode
invoke-wmimethod -path "win32_service.name='spooler'" -name startservice
#bzw.
invoke-wmimethod -path "win32_service.name='spooler'" -name stopservice
die Instance, auf die die Methode angewendet werden soll, wird hier nach dem Parameter -path definiert und die Methode nach dem Parameter -name und das alles in einer Zeile!
Beispiel 5: Hinzufügen eines Clients in eine Domäne mit der Methode JoinDomainOrWorkGroup() der WMI Klasse Win32_ComputerSystem und Reboot mit der Klasse Win32_OperatingSystem
$Domain="dom1.local"
$Password="PassWord123"
$Username="dom1\administrator"
$option = 1
# Bedeutung der Optionen unter msdn.microsoft.com/en-us/library/aa392154(VS.85).aspx
#JoinDomain über die Klasse Win32_ComputerSystem
$computer = Get-WmiObject Win32_ComputerSystem
$computer.JoinDomainOrWorkGroup($domain ,$password, $username, $null, $option)
# Die 4.-te Option muss $null sein, sonst gibts eine Fehlermeldung
# Reboot über die Klasse Win32_OperatingSystem
$OS=gwmi -Class Win32_OperatingSystem
$OS.psbase.scope.options.enableprivileges = $true
$OS.Reboot()
Beispiel 6: Entfernen eines Clients aus der Domäne mit WMI
$Password="PassWord123"
$Username="dom1\administrator"
#0 - computerkonto bleibt erhalten
#4 - computerkonto wird in der domäne gesperrt
$option=0
# Bedeutung der Optionen unter msdn.microsoft.com/en-us/library/aa393942(VS.85).aspx
$computer = Get-WmiObject Win32_ComputerSystem
$computer.UnJoinDomainOrWorkGroup($password, $username, $option)
Anmerkung: Seit Powershell V2.0 gibt es zum Hinzufügen eines Clients das cmdlet "Add-Computer", das die Aufgabe in einem Einzeiler erfüllt
#aus der Powershellhilfe
get-help Add-Computer
#Ausgabe gekürzt
-------------------------- BEISPIEL 4 --------------------------
C:\PS>Add-Computer -domainname Domain02 -OUPath OU=testOU,DC=domain,DC=Domain,DC=com
Beschreibung
-----------
Dieser Befehl fügt die Computer "Server01" und "Server02" der Domäne "Domain02" hinzu. Dabei wird mit dem Befehl "O
UPath" die Organisationseinheit für die neuen Konten angegeben.
analog zum Entfernen eines Rechner das cmdlet "Remove-Computer"
#aus der Powershellhilfe
get-help Remove-Computer
#Ausgabe gekürzt
-------------------------- BEISPIEL 2 --------------------------
C:\PS>remove-computer -credential domain01\admin01 -passthru -verbose
Beschreibung
-----------
Mit diesen Befehlen wird der lokale Computer aus der Domäne entfernt, der er angehört.
2.5 EventQueries
Vielleicht etwas weniger bekannt ist die Eigenschaft von WMI sogenannte Events überwachen und darauf reagieren zu können. Dazu ist erstmal notwendig zu wissen, welche dieser Events es im System (Windows) gibt und wie man darauf zugreift.
Die Antwort liefert diese Tabelle
Da das Oberkapitel hier noch lautet "2. Standard Abfragen in WMI", sind hier im folgenden nur relativ kurz die einfachen Events beschrieben wenn eine Instanz einer Klasse verändert/ gestartet oder beendet wird.
Ein kurzer Auszug aus der eben genannten Tabelle mit den Klassen, auf die ich gleich etwas näher eingehen werde
Reports an instance creation event, which is a type of intrinsic event that is generated when a new instance is added to the namespace. | |||
Reports an instance deletion event, which is a type of intrinsic event generated when an instance is deleted from the namespace. | |||
Reports an instance modification event, which is a type of intrinsic event generated when an instance changes in the namespace. | |||
Serves as a base class for all intrinsic events that relate to an instance. | |||
mit diesen Systemklassen (Eventklassen) können Events (Erstellen, Löschen, Verändern) von Instanzen überwacht werden. "__InstanceOperationEvent" ist die Parentklasse der 3 vorigen Klassen, dadurch können mit dieser Klasse alle 3 vorigen Eventtypen gleichzeitig überwacht werden.
Allerdings müssen die zurückgegeben Events, von denen es ziemlich viele aus unterschiedlichen Klassen gibt, eingegrenzt werden. Dies geschieht mit dem sogenannten ISA-Operator (hat nichts zu tun mit dem ISA Backoffice Server!), der die Ausgabe auf diejenigen Events filtert, die von der TargetInstance win32_service erzeugt werden.
Jetzt fehlt nur noch die geeignete Methode, um die mit den bisherigen Informationen zusammengebaute Abfrage, an den WMI-Service zu senden.
Die letzten Zeilen werden anhand von Beispielen sicher schnell deutlicher:
Beispiel 1: Alle von einer WMI-Klasse erzeugten CreationEvents überwachen und eine Aktion ausführen
$query='Select * From __InstanceCreationEvent WithIn 10 Where TargetInstance ISA "Win32_Process"'
$action={out-host -inputobject "ein Prozess wurde um $(get-date) gestartet "}
register-wmiEvent -query $query -action $action
#mögliche Ausgabe beim Starten eines Prozesses
ein Prozess wurde um 03/30/2010 16:55:38 gestartet
Erklärungen zum Skript:
Die WMI-Query enthält die Systemklasse __InstanceCreationEvent. Die von dieser Klasse erzeugten Events werden durch den ISA-Operator (TargetInstance ISA) auf die Events gefiltert, die von Win32_Process kommen. "WithIn 10" ist der Monitoring Zeitraum in Sekunden, also alle 10 Sekunden wird das System auf Veränderungen geprüft. Ein Prozess, der zwei Sekunden nach der letzten Prüfung gestartet wurde und 5 Sekunden später beendet wurde, würde bei diesem Beispiel mit dem 10 SekundenFenster nicht gemonitort
$action: Die Aktion, die bei Eintritt des Events ausgeführt wird. Leider lässt sich wohl der Prozessname selbst nicht ausgeben.
Starten der Überwachung mit register-wmiEvent
Anmerkung: will man den Prozessnamen auch erkennen, so muss man entweder eine Überwachung speziell auf einen Prozess richten, wie im nächsten Beispiel, oder über die Net-Klasse System.Management.ManagementEventWatcher gehen (siehe Kapitel Prozesse
Beispiel 2: Von einer WMI-Klasse erzeugten und gefilterten CreationEvents überwachen und die Ergebnisse in ein Event schreiben
$query="Select * From __InstanceCreationEvent WithIn 10 Where TargetInstance ISA 'Win32_Process' AND TargetInstance.Name='Notepad.exe'"
$SourceIdentifier="ProzesseNP"
register-wmiEvent -query $query -SourceIdentifier $SourceIdentifier
get-event -SourceIdentifier "ProzesseNP"
unregister-event -SourceIdentifier $SourceIdentifier
Die WMI-Query enthält die Systemklasse __InstanceCreationEvent. Aus den von dieser Klasse erzeugten Events werden durch den ISA-Operator (TargetInstance ISA) diejenigen Events gefiltert, die von Win32_Process kommen und deren Processname "notepad.exe" lautet.
"WithIn 10" ist der Monitoring Zeitraum in Sekunden (alle 10 Sekunden wird das System auf Veränderungen geprüft). Ein Prozess, der zwei Sekunden nach der letzten Prüfung gestartet wurde und 5 Sekunden später beendet wurde, würde bei diesem Beispiel mit dem 10-Sekundenfenster nicht gemonitort
Die Events werden unter dem Namen "ProzesseNP" gesammelt
Starten der Überwachung
Auslesen des SourceIdentifiers "ProzesseNP"
deregistrieren des SourceIdentifiers "ProzesseNP", d.h. Events werden nicht mehr gesammelt
Anmerkung: Der -action Parameter verhindert die Funktion der -SourceIdentifier Parameters
Klassen, die in den obigen Beispielen analog verwendet werden können
Shares | win32_share |
Prozesse | win32_process |
Dienste | win32_service |
Dateien | CIM_DirectoryContainsFile |
Ein Beispiel für die Überwachung von Diensten findet ihr im
Näher auf die FileÜberwachung gehe ich im Kapitel
Beispiel 3a: Anzeige aller registrierten Event-Subscriber
Get-EventSubscriber | ft SubScriptionID,SourceIdentifier -auto
#mögliche Ausgabe
SubscriptionId SourceIdentifier
-------------- ----------------
14 b56760de-98c7-4740-bc30-7dfa35d98f4e
6 MyFileMon1
8 MyFileMon3
15 ee550122-31ec-468c-8d98-1a981f3fe307
18 5bbf58b5-7b8b-4e8e-adf4-62eec131416d
19 17c80820-5b9a-49c8-83c0-68e67d77e66c
Die Events sind nur für die aktuelle Powershellsession registriert.
Beispiel 3b: Löschen aller registrierten Event-Subscriber
Get-EventSubscriber | foreach{Unregister-Event $_.SourceIdentifier}
#ohne Ausgabe
2.6 Schema Queries
Die hier verwendete Bedeutung von Schema bezieht sich auf das Schema von WMI-Klassen und hat mit dem Schema von ActiveDiectory überhaupt nichts zu tun. (siehe auch
Schema Queries haben zwei Einsatzzwecke:
1.-ter Einsatzzweck: WMI-Klassen per Skript erforschen. Man erstellt in einer Schemaquery nicht wie in einer Dataquery ein Objekt von einer Klasse, sondern erstellt eine Instanz der Klasse selbst und kann damit Namespaces, Eigenschaften und Methoden von Klassen oder Klassenhierarchien untersuchen.
Der Einsatz von SchemaQueries dafür ist im täglichen Geschäft wahrscheinlich eher seltener, da erstens für die meisten WMI-Klassen in der MSDN eine ausführliche Dokumentation bereitsteht und zweitens -falls diese Dokumentation nicht vorhanden ist- mit den im Kapitel
2.-ter Einsatzzweck: Um statische Methoden von Klassen wie das Starten von Prozessen aufrufen zu können, muss man zuerst eine Instanz der Klasse selbst erstellen, um darauf eine statische Methode wie "create(Instanz) oder start(Instanz) anwenden zu können.
2.6.1 Mit SchemaQueries Klassen erforschen
Schemaqueries ähneln Dataqueries. Die eingesetzte Klasse lautet „meta_class“, die die Abfrage zur Schemaabfrage macht
Beispiel 1: Alle Klassen des Namespaces “root/wmi”
$NameSpace="root/wmi"
$query="Select * From Meta_Class"
Get-WMIObject –query $query -namespace $Namespace
Beispiel 2a: Beschränkung der Ausgabe auf eine Klasse mit Hilfe der Eigenschaft __Class von meta_class
$namespace="root/cimV2"
$query=” Select * From Meta_Class Where __Class='Win32_LogicalDisk'"
$class=Get-WMIObject –query $query -namespace $namespace
$class.properties | select name
#Ausgabe gekürzt
Name
----
Access
Availability
BlockSize
Beispiel 2b: Beschränkung der Ausgabe auf eine Klasse mit Hilfe der Eigenschaft __This ISA von meta_class
Anstelle der Eigenschaft __Class wird häufiger der der ISA Operator zusammen mit der Eigenschaft __This verwendet
$namespace="root/cimV2"
$query=” Select * From Meta_Class Where __This ISA 'Win32_LogicalDisk'"
$class=Get-WMIObject –query $query -namespace $namespace
"Diese Klasse hat $
"Diese Klasse hat $class.methods.count Methoden"
#Ausgabe
Diese Klasse hat 40 Eigenschaften
Diese Klasse hat 5 Methoden
Beide Eigenschaften in Beispiel 2a und Beispiel 2b arbeiten identisch und schränken die Ausgabe auf eine bestimmte Klasse ein
Beispiel 3: Alle TOP-Klassen des Namespaces "root/cimV2"
$Query= "Select * From Meta_Class Where __Superclass Is Null"
Get-WMIObject –query $query -namespace root/cimV2 | sort
#Ausgabe gekürzt
...
Win32_NTLogEvent {} {Category, CategoryString, ComputerName, Data...}
Win32_NTLogEventComputer {} {Computer, Record}
Win32_NTLogEventLog {} {Log, Record}
...
Die WMI-Klassen sind hierarchisch aufgebaut. Superklassen oder TOP-Klassen sind Klassen, die keine übergeordneten Klassen besitzen, aus denen sie sich ableiten. Wieder ein eher etwas thoretisches Wissen
Beispiel 4: eine Instanz einer Klasse selbst erstellen und darauf eine (statische) Methode anwenden
$query="Select * From Meta_Class Where __Class = 'Win32_process'" (siehe 2.6.1)
$class=Get-WMIObject –query $query
$class.create("notepad.exe")
Alternativ stehen natürlich auch die .Net Methoden oder die cmdlets Start-Process und Start-Job zum Starten eines Prozesses zur Verfügung. Siehe Kapitel
2.6.2 Mit SchemaQueries neue Instanzen einer Klasse erstellen
Um Schema Queries auszuführen, gibt es eine weitere Schreibweise als im obigen Kapitel , die direkt die .Net Syntax benutzt. Nach meinem persönlichen Geschmack ziehe ich die Programmierung mit cmdlets vor, aber da viele Beispiele aus dem Internet den Typeaccelrator [wmiClass] (vgl. Kapitel "Arbeiten mit .net , dort Abschnitt 3) nutzen, sollte man wissen, was eingentlich dahinter steckt.
Beispiel 1: eine Instanz einer Klasse selbst erstellen und darauf eine (statische) Methode (Starten von Notepad) anwenden
$class=[WmiClass]'win32_process' # ausführlicher: $class=[WmiClass] "\\<computernamename>\ROOT\cimv2:Win32_Process"
$class.create("notepad.exe")
Beispiel 2: Eine Objektinstanz (Share C$) erstellen und die Eigenschaften der Instanz abfragen
$instanz=[wmi]'\\.\root\cimv2:Win32_Share.Name="c$"'
#$instanz=[System.Management.ManagementObject]'\\.\root\cimv2:Win32_Share.Name="test"'
$instanz.properties | ft Name,value -auto
#getestet unter PSH V2.0
#mögliche Ausgabe
Name Value
---- -----
AccessMask
AllowMaximum True
Caption Standardfreigabe
Description Standardfreigabe
InstallDate
MaximumAllowed
Name C$
Path C:\
Status OK
Type 2147483648
An den Beispielen sollte man erkennen, dass [System.Management.ManagementObject] vollkommen gleichbedeutend zum TypeAccelator [wmiclass] benutzt werden kann.
Ein weiteres Beispiel, wie man völlig neues Share erstellen kann, findet ihr unter
2.7 Associators of
Mit dem "Associator of" Kommando lassen sich WMI-Klassen kombinieren oder mappen. Mit der ersten Klasse definiert man die interessierende Instanz, mit der zweiten Klasse bekommt man die interessierenden Eigenschaften. Das "Mapping" erfolgt über eine dritte WMI-Klasse, die Associatorklasse.
Oft bringt der Einsatz des "Associators of" Kommandos und eine Standardabfrage mit "Select * from win32_*" das gleiche Ergebnis.
2.7.1 Beispiele zum "Associator of" Kommando
Beispiel 1a: Welches Verzeichnis liegt hinter dem Sharenamen "temp" und welche Eigenschaften hat das Share
Erste Klasse, mit der die Instanz definiert wird : Win32_Share
Zweite Klasse, die kombiniert werden soll : Win32_Directory (taucht im AssociatorSkript nicht auf!)
Dritte Klasse, die das Mapping übernimmt : Win32_ShareToDirectory
Mit dem "Associator of" Kommando
$query="ASSOCIATORS OF {Win32_Share.Name='temp'} WHERE AssocClass=Win32_ShareToDirectory"
Get-WmiObject -Query $query
Alternativ mit Get-WmiObjekt oder [wmi]
$share=gwmi -query "Select * from win32_share where name='WMI-Share'"
#$share=[wmi]"win32_share.name='WMI-Share'" #gleichwertig
$SharePath=$($share.path).replace("\","\\") #Bei pathangaben müssen zwei "\" stehen
$query= "select * from win32_directory where name='$sharepath'"
Get-WmiObject -query $query
#Ausgabe beider Varianten
# Eigenschaften der Win32_Directory Klasse der Instanz C:\temp
Hidden : False
Archive : False
EightDotThreeFileName : c:\temp
FileSize :
Name : c:\temp
Compressed : False
Encrypted : False
Readable : True
Die spanndende Frage beim Arbeiten mit "Associator Of" ist, woher man die passende AssocClass bekommt. Ich benutze als Quelle den "WMI Object Browser" aus den WmiTools gefunden, oder auch das "WMI CIM Studio", welches ohne Instanzen arbeitet.
Am Ende dieses Kapitels in 2.7.2 zeige ich den Einsatz Schritt für Schritt.
Beispiel 1b: Welche Shares liegen auf einem Verzeichnis
Das Beispiel hat jetzt nichts mit dem "Associators of" - Kommando zu tun, sondern ist Ergänzung zum Beispiel 1a gedacht.
gwmi -query "Select * from win32_share where path= 'C:\\temp'" | select name
#alternativ
$path="'C:\\temp'"
$query="Select * from win32_share where path= $path"
get-wmiobject -query $query | select name
Beispiel 2: Welche User greifen von welchen Computern auf ein Share zu
$query="ASSOCIATORS OF {Win32_Share.Name='WMI-Share'} WHERE AssocClass=win32_connectionshare"
Get-WmiObject -Query $query | select username,computername
username computername
-------- ------------
user1 192.168.14.38
user2 192.168..12.126
Beispiel 3: Auslesen aller AD-Gruppen
$Query="ASSOCIATORS OF {Win32_NTDomain.Name='Domain: DOM1'} WHERE assocClass=Win32_GroupInDomain"
Get-WmiObject -Query $query | get-member
#Ausgabe
TypeName: System.Management.ManagementObject#root\cimv2\Win32_Group
Name MemberType Definition
---- ---------- ----------
Rename Method System.Management.ManagementBaseObject Rename(System.String Name)
Caption Property System.String Caption {get;set;}
Description Property System.String Description {get;set;}
Domain Property System.String Domain {get;set;}
InstallDate Property System.String InstallDate {get;set;}
LocalAccount Property System.Boolean LocalAccount {get;set;}
Name Property System.String Name {get;set;}
SID Property System.String SID {get;set;}
SIDType Property System.Byte SIDType {get;set;}
Status Property System.String Status {get;set;}
$Query="ASSOCIATORS OF {Win32_NTDomain.Name='Domain: DOM1'} WHERE assocClass=Win32_GroupInDomain"
Get-WmiObject -Query $query | select Name,description
#Ausgabe gekürzt
name description
---- -----------
Zertifikatherausgeber Mitglieder dieser Gruppe dürfen Zertifik...
RAS- und IAS-Server Server in dieser Gruppe können auf die R...
Zulässige RODC-Kennwortreplikationsgruppe Mitglieder dieser Gruppe können Kennwört...
Abgelehnte RODC-Kennwortreplikationsgruppe Mitglieder dieser Gruppe können Kennwört...
DnsAdmins Gruppe "DNS-Administratoren"
Laut Technet sind AD-Abfragen mittels WMI nicht so optimiert, wie LDAP-Queries. siehe
Beispiel 4: Ermitteln aller an einem Computer angemeldeten Useraccounts (Domaincontroller oder Client)
$Computer = "dc1"
$SessionIDs=get-wmiObject -class "win32_logonsession" -namespace "root\CIMV2" -computer $Computer
$SessionIDs | %{
$query="Associators of {win32_logonsession.LogonID=$($_.LogonID)}"
get-wmiobject -query $query -computer $Computer |?{$_.__class -eq "Win32_UserAccount"} |select caption}
#Ausgabe
caption
-------
DOM1\Admin2
DOM1\User1
DOM1\Administrator
2.7.2 Einsatz des WMI Object Browsers
Der WMI Object Browser ist Teil der WMI Tools, die man sich unter dem Namen "WMI Administrative Tools" bei
Wenn das Tool nicht sauber läuft, überprüft bitte den Browser nach den Sicherheitseinstellungen und wechselt zwischen dem InternetExplorer und Firefox.
3. Syntaxvarianten von WMI in Powershell
Powershell bietet eine ganze Menge identischer Syntaxvarianten für das Skripten mit WMI. Auf der einen Seite kann man mit sehr kurzen Kommandos mächtige WMI-Befehle zusammenbauen, anderseits leidet mit diesen Abkürzungen die Orientierung.
Ich arbeite meist mit den von Powershell bereitgestellten cmdlets, seltener mit den sogenannten TypeAccelerators und ihren zugehörigen .Net Klassen. Ich empfinde die Syntax mit den Positionsparametern der cmdlets einprägsamer als die Klassenschreibweise. Ebenso die Tatsache, die Onlinehilfe zu den cmdlets mit get-help immer schnell verfügbar zu haben ist angnehmer, als im Internet nach den passenden Informationen suchen zu müssen.
In vielen Beispielen aus Büchern oder dem Internet werden beide Schreibweisen intensiv genutzt, so dass man mit beiden Varianten zurecht kommen muss.
3.1 WMI-Befehle
3.1.1 TypeAcceleratoren/ TypeShortcuts
TypeAccelerators, auch Typeshortcuts genannt, sind Aliase für .Net Klassen. Ich verwende nur diese Kurzformen und habe bisher in keinem Beispiel die ausgeschriebenen .Net Klassennamen gesehen.
Accelerator | .Net Klasse |
[wmi] | [System.Management.ManagementObject] |
[wmiclass] | [System.Management.ManagementClass] |
[wmisearcher] | [System.Management.ManagementObjectSearche |
3.1.2 cmdlets
cmdlet | Alias | Kurzbeschreibung |
Get-WmiObject | gwmi | Das Universalcmdlet für WMI. Mehr braucht man nicht |
Invoke-WmiMethod | iwmi | cmdlet zum Aufruf von WMI-Methoden |
Eine Beschreibung der Verbesserungen in Powershell V2.0, sowie einige anschauliche Beispiele findet man unter
3.2 WMI Syntax (Instanzbasiert)
In diesem Abschnitt will ich anhand von Win32_Share Beispielen verschiedene Syntaxvarianten zeigen, die identische Ergebnisse liefern. Die Performance mit der einen oder anderen Variante habe ich nicht untersucht, glaube aber, dass keine entscheidende Unterschiede auftreten.
Die Beschreibung der Methoden von Win32_Share findet man unter
MSDN:SetShareInfo Method of the Win32_Share Class
3.2.1 Instanz eines Shares erstellen
In diesem und allen weiteren Beispielen lautet mein Sharename "WMI-Test" und liegt lokal auf "C:\temp"
Beispiele 1: cmdlet "Get-WmiMethod" (gwmi)
$share=gwmi -query "Select * from win32_share where name='WMI-Test'"
$share.delete() #Löschen der Instanz aus dem Arbeitsspeicher am Ende des Skripts
$Computer="."
$Namespace="Root\cimV2"
$Query="Select * from win32_share where name='WMI-Test'"
$share=gwmi -query $Query -NameSpace $Namespace -computer $Computer
$Share.delete() #Löschen der Instanz aus dem Arbeitsspeicher am Ende des Skripts
Mit den sogenannten Positionsparametern lässt sich "Get-WmiObject" bequem parametrisieren. Weitere Parameter wie Credentials oder Privileges können direkt im Befehl oder als Variablen an WMI übergeben werden.
In der einfachen Parameterübergabe liegt einer der grossen Vorteile gegenüber dem Arbeiten mit TypeAcceleratoren und den .Net Klassen (siehe kommende Beispiele)
Beispiele 2: TypeAccelerator [wmi]
$share=[wmi]"win32_share.name='WMI-Test'"
#$share=[wmi]"\\Computer1\root\cimV2:win32_share.name='WMI-Test'"
$share=[wmi]"\\$Computer\$($NameSpace):win32_share.name=$ShareName"
$share.delete() #Löschen der Instanz aus dem Arbeitsspeicher am Ende des Skripts
$Computer="Computer1"
$Namespace="root\cimV2"
$ShareName="'WMI-Test'"
$share=[wmi]"\\$Computer\$($NameSpace):win32_share.name=$ShareName"
$share.delete() #Löschen der Instanz aus dem Arbeitsspeicher am Ende des Skripts
Beim Parametrisieren mit Variablen muss man bei der Verwendung von [wmi] auf Hochkommas und Backslashes aufpassen!
Sollen Namespace oder weitere Parameter benützt werden, verliert diese Syntax ihre Einfachheit sehr schnell.
Beispiel 3: TypeAccelerator [wmiSearcher]
$query=[wmisearcher] "select * from win32_share where name='WMI-Test'"
$share=$Query.get()
3.2.2 Methoden auf eine existierende Instanz anwenden
In diesem und allen weiteren Beispielen lautet mein existierender Sharename "WMI-Share" und liegt lokal auf "C:\temp". Als Methode verwende ich "SetshareInfo" von win32_share, um die Beschreibung "Das ist ein Test" auf das Share zu setzen.
Die drei obligatorischen, sowie der vierte optionale Parameter von SetshareInfo sind unter
Beispiel 1: Setzen einer ShareBeschreibung mit cmdlet "Get-WmiMethod"
$Object=Get-WMIObject –query "Select * from win32_share where name='temp'"
$Object.SetShareInfo($null,"Das ist ein Test",$null)
Beispiel 2: Setzen einer ShareBeschreibung mit cmdlet "Invoke-WmiMethod"
iwmi -path "win32_share.name='temp'" -name SetShareInfo -argumentlist $null,"Das ist ein Test",$null
Das cmdlet "Invoke-WmiMethod" ist in Powershell V2.0 hinzugekommen. Es bietet zwar keine neue Funktionalitäten, soll aber den Aufruf von Methoden vereinfachen und klarer machen, siehe
Beispiel 3: Setzen einer ShareBeschreibung mit dem TypeAccelerator [wmi]
([wmi]"win32_share.name='temp'").SetShareInfo($null,"Das ist ein Test",$null)
3.3 WMI Syntax (statisch)
(siehe eventuell nochmal Abschnitt 1.3, "Kuchenbacken" zum Thema "statisch")
3.3.1 Instanz einer Klasse erstellen (=SchemaQuery)
Beispiel 1: Get-WmiMethod (gwmi)
(siehe Abschnitt 2.6 mit genaueren Informationen)
$class=gwmi -query "Select * From Meta_Class Where __CLASS='Win32_Share'"
$class=gwmi -query "Select * From Meta_Class Where __THIS ISA 'Win32_Share'"
Beispiel 2: TypeAccelerator [wmiClass]
$class=[wmiClass]"win32_share"
In dem Fall muss man anerkennen, dass der TypeShortCut wirklich das Leben vereinfacht.
3.3.2 Ein neues Objekt aus einer Klasse erstellen (statische Methode)
Beispiel 1: Share Erstellen mit Get-WmiMethod (gwmi)
$Verzeichnis="C:\temp"
$ShareName="WMIShare"
$ShareType=0 #Standardshare"
$MaximumAllowed=8
$description="Das ist ein Test"
$Password=""
$Access=$Null
$class=gwmi -query "Select * From Meta_Class Where __CLASS='Win32_Share'"
$return=$class.create($Verzeichnis,$ShareName,$ShareType,$MaximumAllowed,$Description,$Password,$Null)
Switch($return.returnvalue)
{
0 {"Share erfolgreich angelegt"}
2 {"Zugriff verweigert"}
8 {"unbekannter Fehler"}
9 {"ungültiger Name"}
22 {"Share exisitiert bereits"}
Default {"bitte in der MSDN nach dem ReturnValue von Win32_Share suchen"}
}
#getestet unter PSH V2.0
Die Reihenfolge der Argumente findet man unter
Mehr Informationen über das Arbeiten mit Shares findet ihr im Kapitel
Beispiel 2: Share Erstellen mit Invoke-WmiMethod (iwmi)
$args= $Null, "Das ist ein Test", 5, "WMI-Share", "", "C:\Temp", 0
iwmi -path Win32_Share -name create -argumentlist $args
Vergleicht man die beiden letzten Beispiele, fällt die unterschiedliche Reihenfolge der Parameter auf. Get-WmiObject verwendet wie beschrieben die Reihenfolge des MSDN. Invoke-WmiMethod dagegen die Reihenfolge, die man aus dem WMI-Tool Wbemtest auslesen kann.
Note. If you are familiar with WMI’s scripting API then you might have noticed that the parameters used by the Invoke-WMIMethod cmdlet are not passed in the same order as they’re passed when you use the Create method and the Scripting API. In this case, Invoke-WMIMethod uses parameters in the order they appear in Wbemtest.exe. Is this true of all WMI methods that use multiple parameters? We’re looking into this right now to verify that. Nevertheless, using the parameter order specified in Wbemtest is a good place to start when working with methods that require multiple parameters.
So how do you check the parameter order in Wbemtest? To begin with, type wbemtest in the Run dialog box. After connecting to the proper namespace, open the class in question, click the method name, and then click Edit Method. In the Method Editor dialog box click Edit Input Arguments. In the Object Editor dialog box, check Hide System Properties and then view the method parameters. It’s a bit of a hassle but, fortunately, most WMI methods require only a single parameter (if that).
Nicht einmal die Technet kann das Verhalten erklären, aber der Hinweis auf wbemtest ist dennoch wertvoll
Beispiel 3: Share erstellen mit TypeAccelerator [wmiClass]
([wmiClass]"win32_share").Create("C:\Temp","WMI-Share",0)
([WmiClass] "\\DC01\ROOT\cimv2:Win32_Share").Create("C:\Temp","WMI-Share",0)
([WmiClass] "Win32_Share").Create("C:\Temp","Das ist ein Test", 0 , 15, "WMI-Share", "", $null)
Zusammenfassung: Die in diesem Kapitel gezeigten Möglichkeiten der Syntax sind sicher nicht vollständig. Wichtig ist zu erkennen, welche Schreibweisen synonym sind.
4 weitere Praxisbeispiele
4.1 Filesystem
Beispiel 1: Defrag mit Win32_Volume und Win32_DefragAnalysis
Ein cooles Beispiel für WMI liefern einmal mehr die Scriptingguys:
Ab Windows7-Client oder Server2003 liefern die WMI-Klassen Win32_Volume und Win32_Defraganalysis detaillierte Informationen über den Fragmentierungszustand einer Partition.
Abhängig von dem Ergebnis des Skripts der Scriptingguys kann man die Partition defragmentieren lassen
$drive=get-wmiobject -class win32_volume -filter "driveletter='e:'" -computername 192.168.1.100
"`n Zustand vorher `n"
$analysis1=$drive.defraganalysis()
$analysis1.defraganalysis | ft FilePercentFragmentation,FragmentedFolders -auto
"`n Zustand nachher `n"
$out=$drive.defrag($false)
$analysis2=$out.defraganalysis
$analysis2 | ft FilePercentFragmentation,FragmentedFolders -auto
#Ausgabe
Zustand vorher
FilePercentFragmentation FragmentedFolders
------------------------ -----------------
0 8
Zustand nachher
FilePercentFragmentation FragmentedFolders
------------------------ -----------------
0 0
Win32_Volume ist erst Windows Vista und Windows Server2003 verfügbar, nicht für WindowsXP!
Wieweit heutzutage eine Festplattendefragmentierung noch notwendig und sinnvoll ist, darüber scheiden sich die Geister. Besser als Geld für kommerzielle DefragSoftware auszugeben, ist ein kleines PS-Skript allemal.
4.2 Informationen zum Betriebssystem
Beispiel 1a: Mit Win32_Systemdriver alle Treiber mit Versionsnummer auslesen
Die WMI-Klasse Win32_Systemtreiber liefert eine ganze Reihe Informationen über die im System befindlichen Dateien. Leider ist die Treiberversion nicht dabei.
Um diese zu erhalten, muss man über die Eigenschaft "pathname" ins Filesystem gehen und die Fileversion der Treiberdatei auslesen.
$drivers=get-wmiobject -query "select name,pathname from win32_systemdriver "
$headline="{0,-30} {1}" -f "Treibername","Treiberversion"
write-host -BackgroundColor darkyellow -foregroundcolor darkred "$headline`n"
$drivers | foreach{
try{
$Driverfileversion=$($(Get-Command $_.PathName).fileversioninfo).fileversion
}
catch{
$Driverfileversion=""
}
"{0,-30} {1}" -f $($_.name),$Driverfileversion
}
#Ausgabe gekürzt
Treibername Treiberversion
Abiosdsk
abp480n5
ACPI 5.1.2600.5512 (xpsp.080413-2111)
ACPIEC 5.1.2600.0 (xpclient.010817-1148)
ActivIdentity USB Reader V3 4.31.00.01
adpu160m
aec 5.1.2601.3142
....
Wie man sieht, existiert nicht zu jedem Treiber auch eine Datei. Da die Fileversionsbestimmung in einem solchen Fall einen Fehler werfen würde, habe ich diese in einen Try-Catch-Block gepackt.
Im
Beispiel 1b: Treiber in HTML-Datei schreiben mit WMIC
Eine andere einfache Möglichkeit sich alle Treiber mit Win32_Systemtreiber mit gewünschten Eigenschaften anzeigen zu lassen, bietet WMIC
Auf Commandline(!) kann man diese Zeile absetzen:
wmic path win32_systemdriver get Name,started,state /Format:HTABLE >c:\drivers.html
ergibt ohne weiteres Zutun eine schön formatierte HTML-Tabelle aller mit "get" ausgewählten Eigenschaften von Win32_SystemDriver
Knoten | Name | Started | State |
V100WPWMK1II328 | Abiosdsk. | FALSE. | Stopped. |
V100WPWMK1II328 | abp480n5. | FALSE. | Stopped. |
V100WPWMK1II328 | ACPI. | TRUE. | Running. |
V100WPWMK1II328 | ACPIEC. | TRUE. | Running |
WMIC ist zwar schon etwas älter, aber immer noch ein mächtiges und dabei recht einfach zu erlernendes Werkzeug.
Vor einiger Zeit habe ich zu WMIC diesen kleinen Artikel mit einigen Beispielen verfasst:
ServerHowto:
Beispiel 2a: Feststellen, ob ein Host virtuell oder physikalisch installiert ist
#Virtual Machine Detection
if((get-wmiobject Win32_computersystem).model -eq "virtual machine")
{
"Diese Maschine ist virtual"
}else{
"diese Maschine ist physikalisch"
}
Beispiel 2b: Feststellen, ob ein Host virtuell oder physikalisch installiert ist und Angabe des Virtualisierers
Über die Bios-Version kann man auf die Virtualiserungssoftware schliessen.
Technet:
#Virtual Machine Detection
if((get-wmiobject Win32_computersystem).model -eq "virtual machine")
{
"Diese Maschine ist virtuell"
$BiosVersion=(get-wmiobject win32_bios).Version
switch($BiosVersion)
{
"VRTUAL - 1000831" {"Virtualisierer: Hyper-V2008BetaorRC0"}
'VRTUAL - 5000805", "BIOS Date: 05/05/08 20:35:56 Ver: 08.00.02"' {"Virtualisierer: Hyper-V2008RTM"}
"VRTUAL - 3000919" {"Virtualisierer: Hyper-V2008R2"}
"A M I - 2000622" {"Virtualisierer: VS2005R2SP1orVPC2007"}
"A M I - 9000520" {"Virtualisierer: VS2005R2"}
"A M I - 9000816" {"Virtualisierer: WindowsVirtualPC"}
"A M I - 6000901" {"Virtualisierer: WindowsVirtualPC"}
"A M I - 8000314" {"Virtualisierer: VS2005orVPC2004"}
"VMware, Inc." {"Virtualisierer: VMWare"}
default {"Die Virtualisierungssoftware kann anhand der Biosversion nicht identifiziert werden"}
}
}else{
"diese Maschine ist physikalisch"
}
#mögliche Ausgabe
Diese Maschine ist virtuell
Virtualisierer: Hyper-V2008R2
Win32_computersystem besitzt noch eine ganze Reihe wertvoller Informationen zum Betriebssystem, siehe MSDN:
5 Wenn's mal hakt
WMI verfügt über eine eigene Loggingfunktionalität, die man aktivieren kann. Eine Beschreibung findet man hier
Ein Diagnosescript in VBS
Wenn WMI gar nicht mehr läuft oder Fehlermeldungen ausgibt, dann hat dieser Artikel einige Rezepte:
Ein etwas älteres, dennoch ganz interessantes FAQ
6 weitere interessante Links
Hier gibt es Quellen, die ich nach der Erstellung des WMI-Kapitels entdeckt habe. Wenn ich Zeit habe, werde ich die Informationen genauer ansehen und reflektieren. Bis dahin stelle ich die Links unsortiert in dieses Kapitel hinein.
Ein ebook zum Thema von Ravikanth Chaganti:





