0.  Einleitung

    1.   WMI-Theorie
    1.1 Namespaces
          Beispiel 1: Namespaces auf einem Rechner ermitteln
          Beispiel 2: Namespace "root/MicrosoftDNS" anstelle des DefaultNameSpaces "root/cimV2" verwenden
    1.2 Provider
          Beispiel 1: Ermitteln der Provider des Namespaces root/cimV2
    1.3 Klassen / 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-Schemaquery

    2.   Standard WMI-Abfragen
    2.1 DataQueries
          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.2 WQL - 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.3 WMI-Abfragen optimieren
    2.4 WMI-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.5 EventQueries
         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.6 SchemaQueries
         2.6.1 SchemaQueries 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.2 SchemaQueries 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.7 Associators of
         2.7.1 Beispiele 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.2 Einsatz des WMI Object Browsers

    3.   Syntaxvarianten von WMI
    3.1 WMI-Befehle
         3.1.1 TypeAcceleratoren/ TypeShortcuts
         3.1.2 cmdlets
    3.2 WMI Syntax (Instanzbasiert)
         3.2.1 Beispiele: Instanz eines existierenden Shares erstellen
                  Beispiele 1: cmdlet "Get-WmiMethod" (gwmi)
                  Beispiele 2: TypeAccelerator [wmi]
                  Beispiel 3: TypeAccelerator [wmiSearcher]
         3.2.2 Methoden 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.3 WMI Syntax (statisch)
         3.3.1 Instanz einer Klasse erstellen (=SchemaQuery)
         3.3.2 Ein 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]

    4.   WMI-Praxisbeispiele
    4.1 FileSystem
          Beispiel 1: Defrag mit Win32_Volume und Win32_DefragAnalysis
          Beispiel 2a: Analysieren eines Remote-Volumes mti dem cmdlet Optimize-Volume
          Beispiel 2b: Defragmentieren eines Remote-Volumes mti dem cmdlet Optimize-Volume
    4.2 Informationen 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 Virtualisierers

    5. Wenn 's mal hakt

    6. weitere interessante Links (|-> 10.03.2011)


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 (UEFI), 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 MSDN: WMI Scripting Primer: Part 1 ab dem Abschnitt "WMI Architecture" etwa in der Mitte des Artikels. Die theoretischen Grundlagen werden hier anschaulich beschrieben (CIMOM / Provider / Managed Resources / CIM / einiges mehr).
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 DMTF (Distributed Management Task Force) die Standards, auf denen WBEM und damit WMI basieren.
 

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 Abschnitt Provider), der wiederum den Zugriff auf Computer, Disks, Files, Folder, Netzwerkkarten, Drucker, Prozesse , Freigaben und vieles mehr bereitstellt. 

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 Windows eigene Tool "wbemtest.exe" ist nicht nicht allzu komfortabel, aber mit etwas Probieren bekommt man viele Informationen über einen Namespace
b) Der WMI-Explorer The PowerShell Guy: PowerShell WMI Explorer Part 1  ist ein recht komfortables und umfangreiches, in Powershell geschriebenes, kostenloses Tool.  Der WMI-Explorer Stürzt bei mir nur relativ häufig ab
c) Eine ganze Sammlung mit den WMI-Tools: Microsoft Download Center: WMI Administrative 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.

Set-StrictMode -Version "2.0"
Clear-Host

$Computer="."
$NameSpaces = Get-WmiObject __NameSpace -Computer $Computer -NameSpace Root  |Select Name
$NameSpaceFullNames = $NameSpaces | ForEach {
  "Root"+'\'+ $_.name
}
$NameSpaceFullNames | Format-Wide {$_} -Column 3 -Force
#Ausgabe

Root\subscription            Root\DEFAULT                 Root\CIMV2                 
Root\Cli                     Root\Nap                     Root\SECURITY              
Root\SmsDm                   Root\SecurityCenter2         Root\RSOP                  
Root\ccm                     Root\WMI                     Root\directory             
Root\Policy                  Root\Interop                 Root\ServiceModel          
Root\SecurityCenter          Root\MSAPPS12                Root\Microsoft

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.

Set-StrictMode -Version "2.0"
Clear-Host

$Computer="Dom1DC01"
$NameSpace="root/MicrosoftDNS"
Get-WmiObject -class MicrosoftDNS_Server -namespace $NameSpace -computer $Computer
#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

Set-StrictMode -Version "2.0"
Clear-Host

$Computer="."
$NameSpace = "root\cimv2"
$Providers = @(Get-WmiObject __Win32Provider -Computer $Computer -NameSpace $NameSpace)
$ProviderNames = $Providers | Sort |  Foreach {$_.Name}
   
$ProviderNames | Format-Wide {$_} -Column 3 -Force
#Ausgabe

CIMWin32                                  Cimwin32A                                DFSProvider                             
DskQuotaProvider                          EventViewerConsumer                      MS_NT_EVENTLOG_EVENT_PROVIDER           
MS_NT_EVENTLOG_PROVIDER                   MS_Power_Management_Event_Provider       MS_Shutdown_Event_Provider              
MS_VIEW_INSTANCE_PROVIDER                 Msft_ProviderSubSystem                   MSIProv                                 
MSVDS__PROVIDER                           MSVSS__PROVIDER                          NamedJobObjectActgInfoProv              
NamedJobObjectLimitSettingProv            NamedJobObjectProv                       NamedJobObjectSecLimitSettingProv       
OSppProvider                              ProviderSubSystem                        RegistryEventProvider                   
RegPropProv                               RegProv                                  ReliabilityMetricsProvider              
RouteEventProvider                        RouteProvider                            SCM Event Provider                      
SECRCW32                                  SessionProvider                          SppProvider                             
Standard Non-COM Event Provider           SystemConfigurationChangeEvents          UserProfileProvider                     
VolumeChangeEvents                        WBEMCORE                                 WhqlProvider                            
Win32_OfflineFilesProvider                Win32_WIN32_TERMINALSERVICE_Prov         Win32_WinSAT                            
Win32ClockProvider                        WMI Kernel Trace Event Provider          WMI Self-Instrumentation Event Provider
WmiPerfClass                              WmiPerfInst                              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 Klassen/ Eigenschaften/ Methoden/ Objekte/ 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

Set-StrictMode -Version "2.0"
Clear-Host

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

Set-StrictMode -Version "2.0"
Clear-Host

$NameSpace="root/cimV2"
$Query=”Select * From Meta_Class Where __Class = 'Win32_Bios'"

$Class=Get-WMIObject –query $Query -namespace $NameSpace
$Class.Properties | Select Name

# identisch zu (Get-WMIObject Win32_Bios).Properties | select Name

#Ausgabe gekürzt

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 MSDN: Win32_Classes, so auch die Klasse Win32_BIOS.

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 Kapitel 1.1 Namespaces) und keine weiteren Überlegungen sind notwendig. Selbstverständlich kann man den Namespace auch im Skript noch einmal hinzufügen, was übrigens viele Skripter auch machen. 

zu b) manch schöne Eigenschaft ist leider erst ab aktuellen OS-Versionen verfügbar. Daher seht in der MSDN nach 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

Set-StrictMode -Version "2.0"
Clear-Host

Get-WmiObject Win32_Bios -Namespace "root/cimV2" | Format-List *
#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: Scriptinternals: MSAcpi_ThermalZoneTemperature

einen kleinen Auszug von dieser Seite:

CriticalTripPoint

 

Datentyp: integer/usint32
Zugriff: Read-only

 

Temperature (in tenths of degrees Kelvin) at which the OS must shutdown the system (ie, critical temperature)

CurrentTemperature

 

Datentyp: integer/usint32
Zugriff: Read-only

 

Temperature at thermal zone in tenths of degrees Kelvin

PassiveTripPoint

 

Datentyp: integer/usint32
Zugriff: Read-only

 

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 MSDN: WQL (SQL for WMI)   (unbedingt mal ansehen!)
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

Set-StrictMode -Version "2.0"
Clear-Host

$Query = "Select * from Win32_Service where Status='OK' and State='stopped'"
Get-WMIObject -query $Query| Format-Table Name, Status,State -auto
#Ausgabe gekürzt

Name                                         Status State  
----                                         ------ -----  
AeLookupSvc                                  OK     Stopped
ALG                                          OK     Stopped
AppIDSvc                                     OK     Stopped
Appinfo                                      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!)

Set-StrictMode -Version "2.0"
Clear-Host
 
#$Pattern = "intel"
$Pattern = "microsoft"
 
$Query = "Select Name,PowerManagementSupported from Win32_NetworkAdapter Where Name Like '%$Pattern%'"
Get-WmiObject -query $Query | Format-Table Name,PowerManagementSupported -auto

#Ausgabe

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 MSDN: LIKE Operator                      

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 

MSDN: WQL Operators

 

Beispiel 3: IstGleich-Bedingung in WhereKlausel

Set-StrictMode -Version "2.0"
Clear-Host


$Query = "select * FROM Win32_LogicalDisk WHERE DriveType = 5"
Get-WmiObject -query "Select * from Win32_LogicalDisk WHERE DriveType = 5"
#"IS 5" wäre hier die falsche Syntax bzw. der falsche Operator

#mögliche Ausgabe


DeviceID     : D:
DriveType    : 5
ProviderName :
FreeSpace    : 0
Size         : 72574976
VolumeName   : SCRIPT_WMI


Beispiel 4: "Ist nicht Null"-Bedingung in WhereKlausel

Hier kommen noch der IS oder der IS NOT Operator. Diese beiden Operatoren müssen eingesetzt werden, wenn eine "NULL-Condition" abgefragt wird, also ob eine Eigenschaft überhaupt einen Wert hat. NULL ist nicht gleich 0 !!

Set-StrictMode -Version "2.0"
Clear-Host

$Query=  "Select * from Win32_NetworkAdapter where MACAddress IS NOT null" #!= geht nicht
Get-WmiObject -query $Query | Format-Table MACAddress,DeviceID -AutoSize
#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.

Microsoft Windows 2000 Scripting Guide: Retrieving Managed Resources Using WMI Query Language (Table 6.9)                    

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"

Set-StrictMode -Version "2.0"
Clear-Host


$NameSpace="Root\Wmi"
$Query="Select * from MSAcpi_ThermalZoneTemperature"

Function GetService
  {
     param($Query)
     $Services=gwmi -query $Query -computer "."
  }
 
$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 MSDN nachvollziehen. 

 

2.4 WMI-Methoden

Viele WMI-Klassen bringen auch recht interessante Methoden mit.


Beispiel 1 : Anzeigen der Methoden der Klasse Win32_Service

Set-StrictMode -Version "2.0"
Clear-Host

 
Get-WMIObject Win32_Service | Get-Member -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()

MSDN: Methods Win32_Service Class


Beispiel 2: Stoppen eines Dienstes mit Get-WmiObject (gwmi)

Set-StrictMode -Version "2.0"
Clear-Host

 
$Service = Get-Wmiobject -query "select * from Win32_Service where Name = 'spooler'"
$Result = $Service.StopService()
 

#identisch mit
#$Result = $Service.InvokeMethod("StopService",$null)
 

"Returnvalue=" + $Result.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  MSDN: StopService Method of the Win32_Service Class


Beispiel 3: Starten eines Dienstes mit Get-WmiObject (gwmi)

Set-StrictMode -Version "2.0"
Clear-Host

 
$Service = Get-WmiObject -query "Select * from Win32_Service where Name = 'spooler'"
$Result = $Service.StartService()
 

#identisch mit
#$Result = $Service.InvokeMethod("StartService", $null)
 

"Returnvalue = " + $Result..Returnvalue
#Ausgabe

Returnvalue=0

Nachzuschlagen kann man die Returnwerte der StartService Methode unter MSDN: StartService Method of the Win32_Service Class


Beispiel 4:  Starten und Stoppen eines Dienstes mit Invoke-WmiMethod (iwmi)

WMI Enhancements in Windows PowerShell 2.0 CTP

Etwas direkter erlaubt das mit Powershell 2.0 hinzugekommene cmdlet "Invoke-WmiMethod" den Aufruf einer Methode

Set-StrictMode -Version "2.0"
Clear-Host

 
$Result = Invoke-WmiMethod -path "Win32_service.Name='spooler'" -name StartService 
$Result.ReturnValue
 

#bzw.
$Result = Invoke-WmiMethod -path "Win32_Service.Name='spooler'" -name StopService 
$Result.ReturnValue

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

Set-StrictMode -Version "2.0"
Clear-Host

$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

Set-StrictMode -Version "2.0"
Clear-Host

$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 MSDN: WMI System Classes (wegen der Darstellung bitte im IE, nicht im Mozilla öffnen!) mit den sogenannten System- oder WMI Eventklassen. Systemklassen beginnen mit zwei Unterstrichen vor dem Klassennamen.
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

__InstanceCreationEvent

Reports an instance creation event, which is a type of intrinsic event that is generated when a new instance is added to the namespace.

__InstanceDeletionEvent

Reports an instance deletion event, which is a type of intrinsic event generated when an instance is deleted from the namespace.

__InstanceModificationEvent

Reports an instance modification event, which is a type of intrinsic event generated when an instance changes in the namespace.

__InstanceOperationEvent

 

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

Set-StrictMode -Version "2.0"
Clear-Host

 
$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 6.2 Monitoring von Prozessen)


Beispiel 2: Von einer WMI-Klasse erzeugten und gefilterten CreationEvents überwachen und die Ergebnisse in ein Event schreiben

Set-StrictMode -Version "2.0"
Clear-Host

 
$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

Technet - Windows Management Infrastructure Blog: Windows Event on File Create?

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 Kapitel Dienste -> 1 Basisbeispiele -> Beispiel 3

Näher auf die FileÜberwachung gehe ich im Kapitel Das FileSystem -> FileMonitoring ein


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-68e67d77e66

Die Events sind nur für die aktuelle Powershellsession registriert.
 

Beispiel 3b: Löschen aller registrierten Event-Subscriber

Get-EventSubscriber | foreach{Unregister-Event $_.SourceIdentifier}

 

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 Kapitel 1.3 Zusammenfassung Klassen/ Eigenschaften...)

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 1.1 Namespaces erwähnten Tools komfortable Hilfsmittel für diese Aufgaben bereitstehen.

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”

Set-StrictMode -Version "2.0"
Clear-Host
 
$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

Set-StrictMode -Version "2.0"
Clear-Host
 
$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

Set-StrictMode -Version "2.0"
Clear-Host
 

$Query=” Select * From Meta_Class Where __This ISA 'Win32_LogicalDisk'"
$Class=Get-WMIObject –query $query -namespace $namespace

"Diese Klasse hat $

 class.properties.count Eigenschaften"
"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"

Set-StrictMode -Version "2.0"
Clear-Host


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

Set-StrictMode -Version "2.0"
Clear-Host

$Query= "Select * From Meta_Class Where __Superclass Is Null"
Get-WMIObject –query $Query -namespace Root/CimV2 | Sort

$Query="Select * From Meta_Class Where __Class = 'Win32_Process'"
$Class=Get-WMIObject –query $Query
$Class.Create("notepad.exe") | Out-Null

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 Prozesse -> 4.2 Prozesse neu starten

 

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'
#$Class = [WmiClass] "\\<computernamename>\ROOT\cimv2:Win32_Process"
$Class.Create("notepad.exe")

Beispiel 2: Eine Objektinstanz (Share C$) erstellen und die Eigenschaften der Instanz abfragen

$Instance = [WMI]'\\.\Root\Cimv2:Win32_Share.Name="c$"'
#$instanz = [System.Management.ManagementObject]'\\.\root\cimv2:Win32_Share.Name="test"'
$Instance.Properties | Format-Table 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 [WMI] benutzt werden kann.

Ein weiteres Beispiel, wie man völlig neues Share erstellen kann, findet ihr unter 3.3.2 Ein neues Objekt aus einer Klasse erstellen (statische Methode) -> Beispiel 1 und Beispiel 2

 

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

Das temp-Share muss natürlich existieren

 

Alternativ mit Get-WmiObjekt oder [WMI]

$ShareName = "temp"
 
$Share = Gwmi -query "Select * from Win32_Share where Name='$ShareName'"
#$Share = [WMI]"Win32_Share.Name='$ShareName'" #gleichwertig
 
$SharePath = $($Share.Path).Replace("\","\\") #Bei pathangaben müssen zwei "\" stehen
$Query = "Select * from Win32_Directory where Name='$SharePath'"
 
Get-WmiObject -query $Query
#mögliche 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.

Set-StrictMode -Version "2.0"
Clear-Host
 
$Path = "'C:\\temp'"
$Query = "Select * from Win32_Share where Path = $Path"
Get-WmiObject -query $Query | select Name

#Ausgabe

 

Name  
---- 
temp  


Beispiel 2: Welche User greifen von welchen Computern auf ein Share zu

Set-StrictMode -Version "2.0"
Clear-Host
 
$ShareName = "temp"
$Query = "ASSOCIATORS OF {Win32_Share.Name='$ShareName'} WHERE AssocClass=Win32_ConnectionShare"
Get-WmiObject -Query $Query | select Username,Computername
username                                computername
--------                                ------------
user1                                   192.168.14.38
user2                                   192.168..12.126


Beispiel 3a: 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 ..)
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;}

 

Beispiel 3b: Auslesen aller AD-Gruppen

$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  http://support.microsoft.com/kb/302857/en-us

Beispiel 4: Ermitteln aller an einem Computer angemeldeten Useraccounts (Domaincontroller oder Client)

Set-StrictMode -Version "2.0"
Clear-Host
 
Function Main{
  $Computer = "."
  Get-LoggedUsers $Computer
}
 
Function Get-LoggedUsers{
   Param ($Computername)
   $SessionIDs=Get-WmiObject -class "Win32_LogonSession" -namespace "Root\CIMV2" -computer $Computername
   $SessionIDs | ForEach{
   $Query="Associators of {Win32_LogonSession.LogonID=$($_.LogonID)}"
   $Return = Get-WmiObject -query $Query -computer $Computer |?{$_.__class -eq "Win32_UserAccount"} |Select  Caption}
   Return $Return
}
 
Main
 
#mögliche Ausgabe

caption
-------
DOM1\Admin3
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 www.microsoft.com/downloads kostenlos downloaden kann. 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

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.ManagementObjectSearcher

 

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 Technet: WMI Enhancements in Windows PowerShell 2.0 CTP
 

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"
$Name="'WMI-Test'"
$Query="Select * from Win32_Share Where Name=$Name"

$Win32_Share=Get-WMIObject -Query $Query -NameSpace $NameSpace -Computer $Computer
#Löschen der Instanz aus dem Arbeitsspeicher am Ende des Skripts
$Win32_Share.Delete() 

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 MSDN: SetShareInfo Method of the Win32_Share Classx beschrieben.
 

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 MSDN: Create Method of the Win32_Share Class

Mehr Informationen über das Arbeiten mit Shares findet ihr im Kapitel Das FileSystem -> 2.4 Freigaben/ Shares


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.

Technet: WMI Enhancements in Windows PowerShell 2.0 CTP

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:
Technet - Scripting Guy: Use PowerShell to Determine Fragmentation of Your Drive

Ab Windows7-Client oder Server2003 liefert die WMI-Klasse Win32_Volume mit der Methode Defraganalysis detaillierte Informationen über den Fragmentierungszustand einer Partition.
Abhängig von dem Ergebnis des Skripts der Scriptingguys kann man die Partition mit der Defrag-Methode defragmentieren lassen

Set-StrictMode -Version "2.0"
Clear-Host

$Volume=Get-WmiObject -class Win32_Volume -filter "Driveletter='c:'" #-computername 192.168.1.100

"Zustand vorher `n"
$Analysis1=$Volume.DefragAnalysis()
$Analysis1.DefragAnalysis | ft FilePercentFragmentation,FragmentedFolders -auto

"`nZustand nachher `n"
$Out=$Volume.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.

Ab Windows 8/ Server2012 macht das cmdlet Optimize-Volume aus dem StorageModule die Sache einfacher

Beispiel 2a: Analysieren eines Remote-Volumes mti dem cmdlet Optimize-Volume

Set-StrictMode -Version "2.0"
Clear-Host

Optimize-Volume C -Analyze -CimSession Dom2DC01 -Verbose
#mögliche Ausgabe

AUSFÜHRLICH: Dom2DC01: Invoking slab consolidation on (C:)...
AUSFÜHRLICH: Dom2DC01: Slab Analysis:  0% complete...
AUSFÜHRLICH: Dom2DC01: Slab Analysis:  100% complete.
AUSFÜHRLICH: Dom2DC01: Post Defragmentation Report:
AUSFÜHRLICH: Dom2DC01: Volume Information:
AUSFÜHRLICH: Dom2DC01: Volume size                 = 89,65 GB
AUSFÜHRLICH: Dom2DC01: Cluster size                = 4 KB
AUSFÜHRLICH: Dom2DC01: Used space                  = 12,52 GB
AUSFÜHRLICH: Dom2DC01: Free space                  = 77,13 GB
AUSFÜHRLICH: Dom2DC01: Slab Consolidation:
AUSFÜHRLICH: Dom2DC01: Space efficiency            = 100%
AUSFÜHRLICH: Dom2DC01: Potential purgable slabs    = 0
  • Der Parameter -Analyze führt zu einer Analyse des angegebenen Volumes.
  • Mit CimSession kann ein Remote-Rechner angesprochen werden
  • Ohne den Positionsparameter -Verbose keinerlei Ausgabe

Technet: Optimize-Volume

Beispiel 2: Defragmentieren eines Volumes mti dem cmdlet Optimize-Volume

Set-StrictMode -Version "2.0"
Clear-Host

Optimize-Volume C -CimSession Dom2DC01 -Verbose
#mögliche Ausgabe

AUSFÜHRLICH: Dom2DC01: Invoking slab consolidation on (C:)...
AUSFÜHRLICH: Dom2DC01: Slab Analysis:  0% complete...
AUSFÜHRLICH: Dom2DC01: Slab Analysis:  100% complete.
AUSFÜHRLICH: Dom2DC01: Retrim:  100% complete.
AUSFÜHRLICH: Dom2DC01: Slab consolidation was skipped because there were few evictable slabs.
AUSFÜHRLICH: Dom2DC01: Post Defragmentation Report:
AUSFÜHRLICH: Dom2DC01: Volume Information:
AUSFÜHRLICH: Dom2DC01: Volume size                 = 89,65 GB
AUSFÜHRLICH: Dom2DC01: Cluster size                = 4 KB
AUSFÜHRLICH: Dom2DC01: Used space                  = 12,52 GB
AUSFÜHRLICH: Dom2DC01: Free space                  = 77,13 GB
AUSFÜHRLICH: Dom2DC01: Allocation Units:
AUSFÜHRLICH: Dom2DC01: Slab count                  = 45904
AUSFÜHRLICH: Dom2DC01: Slab size                   = 2 MB
AUSFÜHRLICH: Dom2DC01: Slab alignment              = 1,00 MB
AUSFÜHRLICH: Dom2DC01: In-use slabs                = 6423
AUSFÜHRLICH: Dom2DC01: Slab Consolidation:
AUSFÜHRLICH: Dom2DC01: Space efficiency            = 100%
AUSFÜHRLICH: Dom2DC01: Potential purgable slabs    = 0
AUSFÜHRLICH: Dom2DC01: Slabs pinned unmovable      = 64
AUSFÜHRLICH: Dom2DC01: Successfully purged slabs   = 0
AUSFÜHRLICH: Dom2DC01: Recovered space             = 0 bytes
AUSFÜHRLICH: Dom2DC01: Retrim:
AUSFÜHRLICH: Dom2DC01: Backed allocations          = 3027
AUSFÜHRLICH: Dom2DC01: Allocations trimmed         = 2469
AUSFÜHRLICH: Dom2DC01: Total space trimmed         = 4,82 GB

Optimize-Volume liefert leider kein Objekt zurück, von dem man die Werte der einzelnen Eigenschaften auslesen und verarbeiten könnte. Stattdessen muss man, wie früher unter VBS,  den OutPut in eine Textdatei umleiten, deren Inhalt man wieder auslesen könnte.

Petri: How to Defrag Drives using Powershell in Windows Server 2012

 

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.

Set-StrictMode -Version "2.0"
Clear-Host

$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
}
#mögliche Ausgabe gekürzt

Treibername                    Treiberversion

1394ohci                       6.2.9200.16384 (win8_rtm.120725-1247)
3ware                          5.01.00.047
ACPI                           6.2.9200.16384 (win8_rtm.120725-1247)
acpiex                         6.2.9200.16384 (win8_rtm.120725-1247)

Bis Windows7 muss nicht zu jedem Treiber auch eine Datei existieren. Da die Fileversionsbestimmung in einem solchen Fall einen Fehler werfen würde, habe ich diese in einen Try-Catch-Block gepackt. Ab Windows8 scheint mir der Try/ Catch-Block nicht mehr notwendig, da jeder Treiber auch eine zugehörige Datei besitzt

Im Kapitel Dienste habe ich gezeigt, wie man die Erfassung der Treiberstände auch als Dienst implementieren kann

MSDN: Win32_SystemDriver Class


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: WMIC - Grundlagen und Beispiele


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: Using and Extending Model Aliases for Hardware Specific Application Installation

#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: Win32_ComputerSystem

 

5 Wenn's mal hakt

WMI verfügt über eine eigene Loggingfunktionalität, die man aktivieren kann. Eine Beschreibung findet man hier
Technetblog - Ask the Performance Team: WMI Debug Logging


Wenn WMI gar nicht mehr läuft oder Fehlermeldungen ausgibt, dann haben diese Artikel einige Rezepte:
Technet: WMI Isn't Working!

Technet: Use PowerShell to Troubleshoot and Repair WMI Errors


Ein etwas älteres, dennoch ganz interessantes FAQ
Technet: Troubleshooting and Tips 


Ein Diagnosescript in VBS
Technet: WMI Diagnosis Utility

 

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: WMI Query Language via PowerShell

Technet: Hey, Scripting Guy! How Do I Migrate My VBScript WMI Queries to Windows PowerShell?

Technet - Scripting Guy! Monitor and Respond to Windows Power Events with PowerShell


Auf das Thema Registry und WMI-Klassen (Win32_Registry und StdRegProv) gehe ich im Kapitel Die Registry -> 2 Bearbeiten der Registry mit WMI genau ein.