WMI/CIM aus C# und PowerShell verwenden — Praxisleitfaden für Hardwareinformationen, Prozessüberwachung und Remoteabfragen

· · Windows, C#, .NET, PowerShell, WMI, CIM, Geschäftsanwendungen, Windows-Entwicklung

„Ich möchte die Seriennummer und den Modellnamen des PCs im Bildschirm einer Geschäftsanwendung anzeigen.“ „Ich möchte den freien Speicherplatz auf einem Server überwachen und eine Warnung ausgeben.“ „Ich möchte erkennen, wenn ein bestimmter Prozess gestartet wird.“ „Ich möchte den Zustand entfernter PCs gebündelt abfragen.“ — Bei der Entwicklung von Windows-Geschäftsanwendungen und Verwaltungswerkzeugen sind solche Anforderungen ein Klassiker. Und die klassische Antwort darauf lautet WMI (Windows Management Instrumentation), standardmäßig benannt als CIM (Common Information Model).

Das Problem ist, dass Informationen rund um WMI aus alten und neuen Quellen gemischt vorliegen. Eine Suche fördert zehn Jahre alte Artikel mit Get-WmiObject zutage, direkt neben Artikeln mit Get-CimInstance, und auch auf der C#-Seite gibt es zwei Linien: System.Management und Microsoft.Management.Infrastructure. Es ist schwer zu erkennen, welche Variante die aktuelle Schreibweise ist und welche „zwar noch funktioniert, aber für neuen Code nicht mehr gewählt werden sollte“. Tatsächlich existiert Get-WmiObject in PowerShell 7 gar nicht mehr, was oft erst bei der Migration eines für 5.1 geschriebenen internen Skripts unangenehm auffällt.

Dieser Artikel richtet sich an C#/PowerShell-Entwickler, die in Geschäftsanwendungen Hardwareinformationen abrufen, Prozesse überwachen und entfernte PCs abfragen. Er ordnet, ausgehend von einem minimalen Verständnis des Aufbaus von WMI/CIM, über die CIM-Cmdlets von PowerShell, die zwei APIs von C#, häufig verwendete Beispielrezepte, Fallstricke bei Leistung, Berechtigungen und 64-Bit-Betrieb bis hin zur Frage, „wann WMI nicht die richtige Wahl ist“, den Stand der Primärquellen zum August 2026 ein.

1. Das Wichtigste zuerst

  • CIM ist der vom DMTF entwickelte Branchenstandard für Verwaltungsinformationen, WMI dessen Microsoft-Implementierung. Die „CIM“-APIs von PowerShell und C# sind die aktuelle Generation von APIs, die diesem Standard folgen und dabei dieselbe WMI-Grundlage ansprechen.1
  • Bei PowerShell sind die CIM-Cmdlets (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent) aktuell. Die alten WMI-Cmdlets (Get-WmiObject und vier weitere) sind ab PowerShell 6 entfernt und funktionieren unter PowerShell 7 nicht.2
  • Der Standardnamensraum ist root/CIMV2, und alltägliche Abfragen bestehen im Kern darin, die Win32_*-Klassen darin mit WQL einzugrenzen.3
  • Remoteabfragen laufen standardmäßig über WSMan (WinRM). Die Angabe von -ComputerName erstellt eine temporäre WSMan-Sitzung. Bei wiederholten Abfragen desselben Ziels ist es für die Leistung bewährte Praxis, eine CIM-Sitzung (New-CimSession) wiederzuverwenden; für ältere Ziele, bei denen WinRM sich nicht konfigurieren lässt, gibt es eine DCOM-Protokolloption.34
  • C# kennt zwei Linien: System.Management (ManagementObjectSearcher) und Microsoft.Management.Infrastructure (CimSession). Beide sind nur unter Windows verfügbar und werden im aktuellen .NET über NuGet eingebunden. Für den produktiven Einsatz von Remoteabfragen und Überwachung eignet sich die MI-API besser, da sie dasselbe Typsystem wie die CIM-Cmdlets teilt.56
  • Erkennen Sie den Start von Prozessen über ein Ereignisabonnement, nicht durch Polling. Das Abonnieren von Win32_ProcessStartTrace muss mit Administratorrechten ausgeführt werden.78
  • Verwenden Sie SELECT * nicht aus Gewohnheit. Die Eingrenzung der übertragenen Daten über -Filter / -Property / -KeyOnly beugt etwa der Hälfte der Leistungsprobleme mit WMI vor.3
  • WMI ist kein Allheilmittel. Für hochfrequente Leistungsüberwachung, das Lesen und Schreiben eigener Anwendungseinstellungen oder einmalige OS-Funktionsaufrufe eignen sich Leistungsindikatoren, die Registrierung, die Win32-API oder dedizierte Cmdlets besser (Entscheidungstabelle in Abschnitt 8).

2. Was WMI/CIM ist — Standard und Implementierung, Namensraum, Klasse, WQL

Zunächst ein einmaliger Überblick über die Begriffe.

Begriff Bedeutung
CIM (Common Information Model) Ein branchenweiter Standard, der Verwaltungsobjekte wie Systeme, Anwendungen, Netzwerke und Geräte darstellt. Entwickelt und gepflegt vom DMTF (Distributed Management Task Force)1
WBEM (Web-Based Enterprise Management) Eine Branchen­initiative, die Standardtechnologien für den Zugriff auf Verwaltungsinformationen in Unternehmensumgebungen entwickelt1
WMI Microsofts Implementierung von WBEM. Stellt Verwaltungsobjekte anhand des CIM-Standards dar und ist fest in Windows integriert1
MI (Windows Management Infrastructure) Die nächste Generation von WMI. Vollständig kompatibel mit dem klassischen WMI; die meisten neuen Provider sind in MI geschrieben1

Als Entwickler sind vier strukturelle Punkte wichtig.

  • Namensraum (namespace): eine Hierarchie, die Klassen bündelt. Für alltägliche Abfragen wird fast ausschließlich root/CIMV2 verwendet, das auch die Vorgabe der CIM-Cmdlets ist.3 Daneben existieren unter anderem root\default (unter anderem für den Registrierungsprovider).
  • Klasse: ein Typ für ein Verwaltungsobjekt, etwa Win32_ComputerSystem (der Computer selbst), Win32_LogicalDisk (ein logisches Laufwerk) oder Win32_Process (ein Prozess). Windows-spezifische Klassen, die von CIM-Standardklassen (wie CIM_LogicalDisk) erben, tragen das Präfix Win32_.9
  • Provider: die Komponente, die den eigentlichen Inhalt einer Klasse bereitstellt. Bei einer Abfrage fragt der Provider das Betriebssystem an Ort und Stelle ab und erzeugt die Werte.
  • WQL: eine SQL-ähnliche Abfragesprache. Wie in SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto' wird eine Klasse wie eine Tabelle behandelt und eingegrenzt. WQL ist auch die Standardabfragesprache der CIM-Cmdlets.3

„Betriebssystem- und Hardwareinformationen über einheitliche Klassen und eine Abfragesprache lesen“ — das ist der Wert, den WMI bietet. Umgekehrt sind Schreib- und Steuerungsvorgänge auf jenen Klassen beschränkt, die Methoden besitzen, die sich über Invoke-CimMethod aufrufen lassen; WMI ist kein Mechanismus, der beliebig alles kann.

3. Nutzung aus PowerShell — CIM-Cmdlets sind aktuell, WMI-Cmdlets sind entfernt

3.1. Die Grundlage: Get-CimInstance

# Nach Klassenname (Standardnamensraum root/CIMV2)
Get-CimInstance -ClassName Win32_OperatingSystem

# Nur den Inhalt der WHERE-Klausel in -Filter schreiben (das Schlüsselwort WHERE selbst nicht angeben)
Get-CimInstance -ClassName Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'"

# Nur die benötigten Eigenschaften abrufen, um die Übertragungsmenge zu reduzieren
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, CreationDate

# Für rohes WQL -Query verwenden
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE 'p%'"

-Filter entspricht genau der WHERE-Klausel von WQL, -Property grenzt die abgerufenen Spalten ein.3 Der Rückgabewert ist ein CimInstance-Objekt, und Datumseigenschaften (wie CreationDate oder LastBootUpTime) kommen bereits als DateTime zurück. Anders als beim alten Get-WmiObject besitzt das abgerufene Objekt keine Methoden direkt, sodass Methodenaufrufe über Invoke-CimMethod erfolgen.

# Eine Methode einer Instanz aufrufen: den Besitzer jedes Prozesses ermitteln
Get-CimInstance -ClassName Win32_Process -Filter "Name = 'notepad.exe'" |
    Invoke-CimMethod -MethodName GetOwner

# Eine statische Methode der Klasse aufrufen: einen Prozess starten
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = 'notepad.exe' }

# Die Klassendefinition (Eigenschaften und Methoden) untersuchen
Get-CimClass -ClassName Win32_Process

3.2. Migrationstabelle von den alten WMI-Cmdlets

Ab PowerShell 6 (einschließlich der aktuellen PowerShell 7) sind die folgenden WMI-v1-Cmdlets entfernt. Dieselbe Funktionalität stellt das Modul CimCmdlets (WMI v2) bereit.2

Alt (bis Windows PowerShell 5.1) Aktuell (CIM-Cmdlets) Anmerkung
Get-WmiObject Get-CimInstance Das Konzept von -Filter / -Query ist dasselbe
Get-WmiObject -List Get-CimClass Klassen erkunden und Definitionen prüfen
Invoke-WmiMethod Invoke-CimMethod Argumente werden als Hashtable über -Arguments @{ } übergeben
Register-WmiEvent Register-CimIndicationEvent Ereignisabonnement (Abschnitt 6.3)
Set-WmiInstance Set-CimInstance Änderung schreibbarer Eigenschaften
Remove-WmiObject Remove-CimInstance Löschen einer Instanz

Die CIM-Cmdlets funktionieren auch unter Windows PowerShell 5.1, weshalb es sich empfiehlt, neu geschriebenen Code auch dann auf der CIM-Seite zu schreiben, wenn er unter 5.1 laufen soll — so entsteht kein Migrationsaufwand für später. Das Gesamtbild von Koexistenz und Migration zwischen 5.1 und 7 ist in „Die Unterschiede zwischen Windows PowerShell 5.1 und PowerShell 7“ zusammengefasst.

4. Remoteabfragen — CIM-Sitzungen (WSMan als Standard) und die DCOM-Option

Ohne Angabe verbinden sich die CIM-Cmdlets über COM mit dem lokalen WMI; wird -ComputerName angegeben, erstellen sie eine temporäre Sitzung über das WSMan-Protokoll (WinRM). Sollen mehrere Vorgänge gegen denselben Computer ausgeführt werden, ist es für die Leistung vorteilhafter, eine CIM-Sitzung zu erstellen und wiederzuverwenden.3

# Für eine einmalige Abfrage -ComputerName (jedes Mal wird eine temporäre Sitzung erstellt)
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName Server01, Server02

# Bei wiederholten Abfragen eine CIM-Sitzung wiederverwenden
$session = New-CimSession -ComputerName Server01
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $session
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" -CimSession $session
Remove-CimSession $session

Für Ziele, bei denen sich WinRM nicht einrichten lässt — etwa ältere Rechner —, lässt sich stattdessen das DCOM-Protokoll wählen.4

$dcom = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName OldServer -SessionOption $dcom

Die Voraussetzungen für eine Remoteabfrage sind die folgenden.

  • WinRM muss auf dem Ziel konfiguriert sein. winrm quickconfig erledigt in einem Schritt den automatischen Start des Dienstes, die Erstellung eines HTTP-Listeners (Standardport 5985) und die Eintragung einer Firewallausnahme.10 Für eine Verbindung über HTTPS (Standardport 5986) reicht dies allein nicht aus — es muss zusätzlich ein Serverzertifikat bereitgestellt und ein HTTPS-Listener etwa mit winrm quickconfig -transport:https gesondert konfiguriert werden.10
  • Die betreffenden Ports müssen auf allen Firewalls entlang des Pfads geöffnet sein. Die praktische Arbeit der Gestaltung und Eintragung eingehender Regeln wird im Artikel „Windows-Firewall und Geschäftsanwendungen“ behandelt.
  • Authentifizierung. In einer Domänenumgebung erfolgt die gegenseitige Authentifizierung über Kerberos. In einer Arbeitsgruppe steht Kerberos nicht zur Verfügung, sodass mitunter eine Eintragung des Ziels in die TrustedHosts-Liste des Clients nötig ist. Diese Liste sollte so eng wie möglich gehalten werden.10
  • Berechtigungen. In der Standardkonfiguration erfolgen Remote-WMI-Abfragen und -Vorgänge grundsätzlich mit einem Konto, das zur Administratorengruppe des Ziels gehört. Um dies für normale Benutzer zu öffnen, ist eine Konfiguration der Zugriffsberechtigungen sowohl bei WinRM als auch im WMI-Namensraum erforderlich.10
  • Da DCOM keinen festen Abhörport besitzt (es verwendet dynamische RPC-Ports), gestaltet sich der Betrieb über eine Firewall hinweg schwierig. Für neu entwickelte Lösungen empfiehlt es sich, WSMan als Standard anzunehmen.

5. Nutzung aus C# — System.Management und Microsoft.Management.Infrastructure

Für den Zugriff auf WMI aus C# gibt es zwei API-Linien. Beide sind ausschließlich unter Windows verfügbar.

  System.Management Microsoft.Management.Infrastructure (MI-API)
Einbindung Im .NET Framework standardmäßig enthalten. Im aktuellen .NET das NuGet-Paket System.Management5 Das NuGet-Paket Microsoft.Management.Infrastructure6
Einstiegsklasse ManagementObjectSearcher (Abfrage durch Übergabe von WQL)5 CimSession (Create → QueryInstances / InvokeMethod / Subscribe)6
Typsystem ManagementObject / ManagementEventWatcher11 CimInstance / CimSessiondieselben Typen wie die CIM-Cmdlets3
Remote DCOM-basiert WSMan-basiert (CIM-Sitzung). Asynchrone Varianten (*Async) verfügbar6
Geeignet für Lokalen Informationsabruf. Erhalt bestehender Codebasis Einbau von Remoteabfragen und Überwachung. Design im Zusammenspiel mit PowerShell

5.1. System.Management: die Grundlagen von ManagementObjectSearcher

WQL wird als Zeichenkette übergeben, das Ergebnis über Get() als Auflistung empfangen.5

// NuGet: System.Management (nur Windows)
using System.Management;

using var searcher = new ManagementObjectSearcher(
    @"root\cimv2",
    "SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");

foreach (ManagementObject disk in searcher.Get())
{
    var freeGb = (ulong)disk["FreeSpace"] / 1024.0 / 1024.0 / 1024.0;
    var sizeGb = (ulong)disk["Size"] / 1024.0 / 1024.0 / 1024.0;
    Console.WriteLine($"{disk["DeviceID"]} frei {freeGb:F1} GB / gesamt {sizeGb:F1} GB");
}

Eigenschaften werden über einen Indexer als object zurückgegeben, sodass Sie in der Klassendokumentation den CIM-Typ nachschlagen müssen (in diesem Beispiel sind FreeSpace und Size vom Typ uint649) und entsprechend casten. Wer hier int annimmt und darauf casted, erhält als klassischen ersten Stolperstein eine InvalidCastException.

5.2. MI-API: die Grundlagen von CimSession

CimSession behandelt lokale und entfernte Zugriffe in derselben Form. Aufzählung, Abfrage, Methodenaufruf, Ereignisabonnement und asynchrone Varianten stehen vollständig zur Verfügung.6

// NuGet: Microsoft.Management.Infrastructure (nur Windows)
using Microsoft.Management.Infrastructure;

// Für lokal CimSession.Create(null), für entfernt einen Computernamen übergeben
using CimSession session = CimSession.Create(null);

IEnumerable<CimInstance> disks = session.QueryInstances(
    @"root\cimv2", "WQL",
    "SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");

foreach (CimInstance disk in disks)
{
    var deviceId = (string)disk.CimInstanceProperties["DeviceID"].Value;
    var free = (ulong)disk.CimInstanceProperties["FreeSpace"].Value;
    Console.WriteLine($"{deviceId} frei {free / 1024.0 / 1024 / 1024:F1} GB");
}

Da hier dieselbe CimInstance verwendet wird, die auch die CIM-Cmdlets von PowerShell zurückgeben, lässt sich der Entwicklungsablauf „erst in PowerShell ausprobieren, dann nach C# übertragen“ direkt fortsetzen. Wer die Verzahnung von C# und PowerShell selbst gestalten möchte, findet weitere Hinweise in „PowerShell aus C# ausführen und die Ergebnisse als Objekte empfangen“.

6. Häufig verwendete Beispielrezepte

6.1. Übersicht der gängigen Klassen

Gewünschte Information Klasse Wichtige Eigenschaften
Hersteller / Modellname Win32_ComputerSystem Manufacturer, Model
Gehäuse-Seriennummer Win32_BIOS SerialNumber
OS-Version / Startzeit Win32_OperatingSystem Caption, Version, LastBootUpTime
Freier Festplattenspeicher Win32_LogicalDisk DeviceID, FreeSpace, Size, DriveType9
Dienststatus Win32_Service Name, State, StartMode
Prozessliste Win32_Process Name, ProcessId, CommandLine

6.2. Der Klassiker der Bestandsverwaltung: Seriennummer, Modellname, freier Speicherplatz

# Modellinformationen und Seriennummer (für den Abgleich mit der PC-Bestandsliste)
$cs   = Get-CimInstance -ClassName Win32_ComputerSystem -Property Manufacturer, Model
$bios = Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber
[pscustomobject]@{
    Manufacturer = $cs.Manufacturer
    Model        = $cs.Model
    Serial       = $bios.SerialNumber
}

# Freier Speicherplatz auf lokalen Laufwerken (DriveType = 3)
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" |
    Select-Object DeviceID,
        @{ Name = 'FreeGB'; Expression = { [math]::Round($_.FreeSpace / 1GB, 1) } },
        @{ Name = 'SizeGB'; Expression = { [math]::Round($_.Size / 1GB, 1) } }

DriveType = 3 steht für „lokales Laufwerk“ und schließt Wechseldatenträger (2), Netzlaufwerke (4) und CD-Laufwerke (5) aus.9 Für die Überwachung genügt es, dieses Skript über eine CIM-Sitzung auf jeden Server auszuführen — das ergibt die Grundlage für eine agentenlose Speicherplatzüberwachung.

6.3. Erkennen des Prozessstarts — Ereignisabonnement

Verwenden Sie kein Polling, bei dem Win32_Process regelmäßig abgerufen und auf Unterschiede geprüft wird, sondern ein Ereignisabonnement. Der einfachste Weg, einen Prozessstart zu erfassen, ist das Abonnieren von Win32_ProcessStartTrace (eine Ereignisklasse des Kernel-Trace-Providers mit Eigenschaften wie ProcessName / ProcessID / ParentProcessID8).

# In einer PowerShell-Sitzung mit Administratorrechten ausführen
$action = {
    $name = $Event.SourceEventArgs.NewEvent.ProcessName
    $id   = $Event.SourceEventArgs.NewEvent.ProcessID
    Write-Host "Prozess gestartet: $name (PID=$id)"
}
Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace `
    -SourceIdentifier ProcessStarted -Action $action

Das Abonnement bleibt so lange aktiv, wie die PowerShell-Sitzung läuft, in der es registriert wurde, und -Action wird bei jedem Prozessstart ausgeführt. Führen Sie den Befehl zum Aufheben des Abonnements nicht direkt im Anschluss in derselben Stapelverarbeitung aus — dadurch verschwindet das Abonnement, bevor die Überwachung überhaupt beginnt. Heben Sie es erst auf, wenn die Überwachung beendet werden soll.

# Wenn die Überwachung beendet werden soll: das Abonnement aufheben
Unregister-Event -SourceIdentifier ProcessStarted

Register-CimIndicationEvent registriert ein Abonnement über einen Klassennamen oder eine WQL-Ereignisabfrage, und der Skriptblock von -Action wird bei jedem eingehenden Ereignis ausgeführt.7 Das Abonnieren dieser Klasse erfordert Administratorrechte.7 Wer das Ereignis empfangen darf, wird über den Sicherheitsdeskriptor der Ereignisklasse geregelt, und ein gewöhnlicher Benutzer ohne erhöhte Rechte erhält eine Zugriffsverweigerung.8

Eine weitere Möglichkeit ist das generische, für beliebige Klassen einsetzbare Instanzerstellungsereignis (__InstanceCreationEvent). Dabei fragt WMI im mit WITHIN angegebenen Intervall ab und wandelt den Unterschied in ein Ereignis um — den Kompromiss zwischen Erkennungsintervall und Last müssen Sie hier selbst festlegen.

# Neue Win32_Process-Instanzen mit einem Abfrageintervall von 5 Sekunden überwachen
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent -Query $query -SourceIdentifier ProcPoll -Action {
    Write-Host "Gestartet: $($Event.SourceEventArgs.NewEvent.TargetInstance.Name)"
}

In C# (System.Management) übernimmt ManagementEventWatcher dieselbe Rolle.11

using System.Management;

// In einem Prozess, der als Administrator ausgeführt wird
var watcher = new ManagementEventWatcher(
    new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
watcher.EventArrived += (_, e) =>
{
    var name = (string)e.NewEvent["ProcessName"];
    var pid  = (uint)e.NewEvent["ProcessID"];
    Console.WriteLine($"Prozess gestartet: {name} (PID={pid})");
};
watcher.Start();
// watcher.Stop() und Dispose beim Beenden der Überwachung nicht vergessen

Bauen Sie dies in eine dauerhaft laufende Überwachungskomponente ein, sollte das Design auch die erneute Registrierung des Abonnements berücksichtigen, wenn es abreißt (bei Dienstneustart oder Fehlern). Die Designüberlegungen zum „Prüfen und Anzeigen von Zuständen“ einschließlich Geräteüberwachung werden in „Best Practices zum Prüfen und Anzeigen des Zustands externer Geräte“ behandelt.

7. Fallstricke — Leistung, Berechtigungen, 64-Bit, Repository und Datumsangaben

7.1. SELECT * und exzessives Polling

Eine WMI-Abfrage bedeutet, dass „ein Provider die Werte an Ort und Stelle erzeugt“ — das kostet etwas. Es gibt zwei klassische Antipatterns.

  • SELECT * aus Gewohnheit. Werden alle Eigenschaften und alle Zeilen von Win32_Process abgerufen, wächst entsprechend die Arbeit des Providers und (bei Remotezugriff) die Netzwerkübertragung. Grenzen Sie Zeilen mit -Filter und Spalten mit -Property ein, und verwenden Sie -KeyOnly, wenn für eine nachfolgende Operation nur die Schlüssel benötigt werden. All dies sind offiziell bereitgestellte Mittel, „um die Objektgröße und den Netzwerkverkehr zu reduzieren“.3
  • Kurzintervall-Polling. Ein Design wie „Get-CimInstance Win32_Process jede Sekunde“ sollte durch das Ereignisabonnement aus Abschnitt 6.3 ersetzt werden. Muss dennoch die Polling-Variante (WITHIN) verwendet werden, sollte das Intervall auf das für die Anforderung tatsächlich ausreichende Maß vergrößert werden.

Auch das wiederholte Aufrufen von -ComputerName für ein entferntes Ziel, einzeln nacheinander, ist verschwenderisch, da bei jeder Abfrage eine temporäre Sitzung erstellt wird — wechseln Sie bei mehreren Vorgängen auf die Wiederverwendung einer CIM-Sitzung.3

7.2. Berechtigungen für Ereignisabonnements

Wie in Abschnitt 6.3 beschrieben, setzt das Abonnieren der Klassenfamilie Win32_ProcessStartTrace Administratorrechte voraus.7 „Auf der Entwicklungsmaschine (mit Administratorrechten ausgeführt) hat es funktioniert, aber in der Umgebung mit gewöhnlichen Benutzerrechten beim Kunden funktioniert die Überwachung nicht“ gehört, neben dem Firewall-Benachrichtigungsdialog, zu den klassischen Stolperfallen. Wird Überwachung in eine Geschäftsanwendung eingebaut, die mit normalen Benutzerrechten läuft, sollte erwogen werden, den Überwachungsteil in einen Windows-Dienst (etwa mit LocalSystem) auszulagern und ihn über Interprozesskommunikation mit der Hauptanwendung zu verbinden.

7.3. 32-Bit/64-Bit und Provider

Unter 64-Bit-Windows existieren einige Provider sowohl in einer 32-Bit- als auch in einer 64-Bit-Version, und standardmäßig antwortet die zur Bitanzahl der aufrufenden Anwendung passende Version.12 Das klassische Beispiel ist der Registrierungsprovider (StdRegProv) unter root\default: Ein Lesezugriff aus einer 32-Bit-Anwendung liefert die Werte der Wow6432Node-Seite (der 32-Bit-Ansicht).12 Wenn „der über WMI gelesene Registrierungswert nicht mit dem in regedit angezeigten Wert übereinstimmt“, ist dies zuerst zu vermuten. Wird die jeweils andere Ansicht benötigt, lässt sie sich über __ProviderArchitecture (und, um sie zu erzwingen, __RequiredArchitecture) im Verbindungskontext explizit anfordern.12 Das Gesamtbild der Bitanzahl-Problematik wird auch in „Win32-APIs sicher aus C# aufrufen — Praxisleitfaden zu P/Invoke“ behandelt.

7.4. Symptome und Behebung bei einem beschädigten WMI-Repository

Die Klassendefinitionen von WMI werden in einem Repository gespeichert (keine einzelne Datei — die Dateien im Repository-Ordner fungieren gemeinsam als Datenbank13). Wird dieses inkonsistent, treten Fehler wie „eine eigentlich vorhandene Klasse wird nicht gefunden“ oder „der Namensraum ist ungültig“ auf, obwohl auf der Anwendungsseite nichts geändert wurde. Zur Diagnose und Reparatur dient winmgmt.exe.13

rem Konsistenzprüfung (Ergebnis "inconsistent" bedeutet, dass eine Inkonsistenz vorliegt)
winmgmt /verifyrepository

rem Konsistenzprüfung und bei Inkonsistenz Neuaufbau (lesbare Inhalte werden übernommen)
winmgmt /salvagerepository

Wichtig ist, das Löschen oder Zurücksetzen des Repositorys nicht als ersten Schritt zu wählen. Über WMI auftretende Fehler können auch andere Ursachen im Betriebssystem haben, und Microsoft weist ausdrücklich darauf hin, dass das Löschen des Repositorys als erste Maßnahme „zu Schäden am System oder an installierten Anwendungen führen kann“.13 Halten Sie die Reihenfolge Prüfung mit /verifyrepository → Reparatur mit /salvagerepository ein.

7.5. Umwandlung des DMTF-Datumsformats

WMI-Datumsangaben werden als Zeichenkette im DMTF-Format der CIM-Spezifikation gespeichert: yyyymmddHHMMSS.mmmmmm±UUU (der abschließende Wert ist der Versatz gegenüber UTC in Minuten, zum Beispiel 20260801100000.000000+540). Zerlegen Sie den Rohwert nicht selbst mit Zeichenkettenverarbeitung, sondern verwenden Sie die Konvertierungs-API.

  • C# (System.Management): ManagementDateTimeConverter bietet die Umwandlung zwischen dem DMTF-Format und DateTime / TimeSpan.11
  • CIM-basierte APIs (Get-CimInstance / MI-API): Datumseigenschaften kommen bereits als DateTime zurück, sodass dieses Problem von vornherein nicht auftritt. (Get-CimInstance Win32_OperatingSystem).LastBootUpTime lässt sich direkt als DateTime in Berechnungen verwenden.

8. Situationen, in denen WMI nicht die richtige Wahl ist — eine Entscheidungstabelle

WMI ist als „einheitliche Leseschnittstelle“ hervorragend, aber nicht immer die optimale Lösung. Hier eine praktische Orientierung für die Wahl der Mittel.

Ziel Geeignetes Mittel Warum nicht WMI
Abruf von Hardwareinformationen und OS-Konfiguration, agentenlose Remoteabfragen WMI/CIM Genau hier liegt die Stärke von WMI — einheitlicher als das einzelne Ansprechen dedizierter APIs
Lesen und Schreiben der Einstellungen der eigenen Anwendung Direkter Registrierungszugriff (Microsoft.Win32.Registry) bzw. Konfigurationsdateien Registrierungszugriff über WMI ist ein Umweg und bringt zudem die Bitanzahl-Problematik aus Abschnitt 7.3 mit
Hochfrequente, kontinuierliche Leistungsüberwachung wie CPU-Auslastung Leistungsindikatoren (System.Diagnostics.PerformanceCounter usw.) Counter sind genau dafür gemacht. Kurzintervall-Polling über WMI ist bei Last und Genauigkeit im Nachteil
Einmaliger OS-Funktionsaufruf oder Verarbeitung mit niedriger Latenzanforderung Die Win32-API (P/Invoke) WMI bringt den Mehraufwand des Umwegs über COM/einen Provider mit
Aufzählung und Steuerung lokaler Prozesse, wenn die Berechtigungen des eigenen Prozesses ausreichen System.Diagnostics.Process Kommt vollständig mit der Standardbibliothek aus, mit weniger Abhängigkeiten
Konfiguration von Windows-Verwaltungsfunktionen wie Firewall oder Netzwerk Dedizierte, CIM-basierte Cmdlets wie Get-NetFirewallRule Ein für den jeweiligen Zweck gepflegtes Cmdlet-Set ist genauer und sicherer, als rohe WMI-Klassen zu durchsuchen
Erkennen von Datei- oder Ordneränderungen FileSystemWatcher Bringen Sie WMI nicht in Bereiche, für die es bereits eine dedizierte API gibt

Die Richtschnur ist einfach: Wo ein dedizierter Mechanismus existiert, verwenden Sie ihn — WMI/CIM ist für übergreifende Abfragen und Remoteabfragen reserviert. Das Get-NetFirewallRule-Beispiel in der letzten Zeile ist intern selbst ein auf CIM aufbauendes Cmdlet-Set — ein Fall von „den Nutzen von WMI/CIM erhalten, ohne es direkt anzufassen“.

9. Zusammenfassung

  • CIM ist der Branchenstandard des DMTF, WMI dessen Microsoft-Implementierung. Sowohl die CIM-Cmdlets von PowerShell als auch die MI-API von C# sind aktuelle Einstiegspunkte, die diesem Standard folgen.
  • In PowerShell sind Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent aktuell. Get-WmiObject und die übrigen WMI-Cmdlets existieren in PowerShell 7 nicht mehr, weshalb neue Skripte auch für 5.1 auf der CIM-Seite geschrieben werden sollten.
  • Remoteabfragen laufen standardmäßig über WSMan (WinRM), bei mehreren Vorgängen sollte eine CIM-Sitzung wiederverwendet werden. Für ein Ziel ohne konfiguriertes WinRM steht DCOM als Ausweichmöglichkeit zur Verfügung.
  • In C# wählen Sie zwischen System.Management (praktisch, lokal ausgerichtet) und Microsoft.Management.Infrastructure (auf Remote und Überwachung ausgerichtet, mit demselben Typsystem wie die CIM-Cmdlets). Beide sind reine Windows-NuGet-Pakete.
  • Überwachen Sie Prozesse über ein Ereignisabonnement, nicht durch Polling. Das Abonnieren von Win32_ProcessStartTrace erfordert Administratorrechte.
  • Vermeiden Sie SELECT * und Kurzintervall-Polling — grenzen Sie mit -Filter / -Property / -KeyOnly ein. Denken Sie daran, dass eine Abfrage aus einem 32-Bit-Prozess vom 32-Bit-Provider bedient wird, dass DMTF-Datumsangaben die Konvertierungs-API benötigen und dass ein beschädigtes Repository in der Reihenfolge Prüfen → Reparieren behandelt werden sollte, nicht durch Löschen.
  • Bringen Sie WMI nicht in Bereiche, für die bereits ein dedizierter Mechanismus existiert (Einstellungen, Leistungsindikatoren, einmalige API-Aufrufe) — reservieren Sie WMI/CIM für übergreifende Abfragen und Remoteabfragen. Das ist die kurze Zusammenfassung, wo es hingehört.

Verwandte Artikel

Verwandte Beratungsleistungen

Die KomuraSoft LLC übernimmt den Einbau von Hardwareinformationsabruf, Prozessüberwachung und Remote-PC-Abfragen mittels WMI/CIM in Geschäftsanwendungen, die Migration von auf Get-WmiObject basierenden internen Skripten zu den CIM-Cmdlets sowie die Ursachenuntersuchung von Fällen wie „auf der Entwicklungsmaschine funktioniert es, beim Kunden erscheint ein Berechtigungsfehler“. Von der Erprobung in PowerShell bis zur vollständigen Umsetzung in C# begleiten wir Sie durchgehend.

  1. Microsoft Learn, About WMI. Dazu, dass WMI Microsofts Implementierung von WBEM ist (einer Branchen­initiative, die Standardtechnologien für den Zugriff auf Verwaltungsinformationen in Unternehmensumgebungen entwickelt), dass zur Darstellung von Verwaltungsobjekten der Branchenstandard CIM (Common Information Model) verwendet wird, der vom DMTF (Distributed Management Task Force) entwickelt und gepflegt wird, dass die Nachfolgeversion MI (Windows Management Infrastructure) vollständig mit dem klassischen WMI kompatibel ist, sowie dazu, dass entfernte WMI-Verbindungen über DCOM erfolgen, mit dem auf WS-Management basierenden WinRM als Alternative.  2 3 4 5

  2. Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. Dazu, dass die WMI-v1-Cmdlets (Register-WmiEvent / Set-WmiInstance / Invoke-WmiMethod / Get-WmiObject / Remove-WmiObject) aus PowerShell entfernt wurden, sowie dazu, dass die Cmdlets des Moduls CimCmdlets (WMI v2) dieselbe Funktionalität mit neuen Funktionen und überarbeiteter Syntax bereitstellen.  2

  3. Microsoft Learn, Get-CimInstance (CimCmdlets). Dazu, dass ohne Angabe von ComputerName oder CimSession eine COM-Sitzung zum lokalen WMI aufgebaut wird und bei Angabe von -ComputerName eine temporäre Sitzung über das WsMan-Protokoll erstellt wird; dazu, dass bei mehreren Vorgängen gegen denselben Computer eine Verbindung über eine CIM-Sitzung aus Leistungsgründen empfohlen wird; dazu, dass -Filter eine WQL-/CQL-WHERE-Klausel ohne das Schlüsselwort WHERE ist; dazu, dass -Property und -KeyOnly die Objektgröße und den Netzwerkverkehr reduzieren können; dazu, dass der Standardnamensraum root/CIMV2 und die Standardabfragesprache (-QueryDialect) WQL ist; dazu, dass die Ausgabe vom Typ Microsoft.Management.Infrastructure.CimInstance ist; zu einem Beispiel des Aufrufs von GetOwner in Kombination mit Invoke-CimMethod; sowie dazu, dass das Cmdlet ausschließlich unter Windows verfügbar ist.  2 3 4 5 6 7 8 9 10

  4. Microsoft Learn, New-CimSessionOption (CimCmdlets). Dazu, dass CIM-Sitzungsoptionen zwei Parametersätze besitzen, für WsMan und für DCOM; dazu, dass -Protocol Dcom / Default / Wsman akzeptiert; zu einem Beispiel, bei dem eine mit New-CimSessionOption -Protocol Dcom erstellte Option an -SessionOption von New-CimSession übergeben wird, um eine DCOM-CIM-Sitzung zu erstellen; sowie dazu, dass die standardmäßige Impersonation-Ebene einer DCOM-Sitzung Impersonate ist.  2

  5. Microsoft Learn, ManagementObjectSearcher Class (System.Management). Dazu, dass dies die gängigste Einstiegsklasse für den Abruf von Verwaltungsinformationen ist, die eine Sammlung von Verwaltungsobjekten anhand einer angegebenen WQL-Abfrage abruft; dazu, dass sie eine ObjectQuery und einen ManagementScope (den WMI-Namensraum) entgegennimmt und über Get() eine ManagementObjectCollection zurückgibt; sowie dazu, dass System.Management.dll als NuGet-Paket System.Management bereitgestellt wird.  2 3 4

  6. Microsoft Learn, CimSession Class (Microsoft.Management.Infrastructure). Dazu, dass Microsoft.Management.Infrastructure.dll als NuGet-Paket Microsoft.Management.Infrastructure bereitgestellt wird; zur Erstellung einer Sitzung über Create(computerName); zur Ausführung einer Abfrage über QueryInstances(namespace, queryDialect, query); sowie dazu, dass EnumerateInstances / GetInstance / InvokeMethod / Subscribe jeweils mit asynchronen Varianten (*Async) bereitgestellt werden und die Klasse IDisposable implementiert.  2 3 4 5

  7. Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). Dazu, dass eine Indikation (ein Ereignis) über Klassennamen oder Abfrageausdruck abonniert und das Abonnement mit -SourceIdentifier benannt wird; zu einem Beispiel des Abonnierens von Win32_ProcessStartTrace mit dem Hinweis, dass dafür PowerShell als Administrator ausgeführt werden muss; zu einem Beispiel, bei dem im Skriptblock von -Action über $Event.SourceEventArgs.NewEvent auf ProcessName / ProcessId zugegriffen wird; dazu, dass bei Angabe von -ComputerName eine temporäre WsMan-Sitzung und ohne Angabe eine lokale COM-Verbindung verwendet wird; sowie dazu, dass Unregister-Event zum Aufheben eines Abonnements dient.  2 3 4

  8. Microsoft Learn, Win32_ProcessStartTrace class. Dazu, dass dies eine Ereignisklasse ist, die den Start eines neuen Prozesses anzeigt, mit Eigenschaften wie ProcessName / ProcessID / ParentProcessID / SessionID / Sid; dazu, dass die Eigenschaft SECURITY_DESCRIPTOR der Deskriptor ist, anhand dessen der Ereignisprovider festlegt, welche Benutzer das Ereignis empfangen dürfen; sowie dazu, dass der Namensraum Root\CIMV2 ist und die Klasse vom Kernel-Trace-Provider (Krnlprov.dll) bereitgestellt wird.  2 3

  9. Microsoft Learn, Win32_LogicalDisk class. Dazu, dass Win32_LogicalDisk eine von CIM_LogicalDisk abgeleitete Klasse ist, die ein lokales Speichergerät darstellt; zu den Werten von DriveType (2 = Wechseldatenträger, 3 = lokales Laufwerk, 4 = Netzlaufwerk, 5 = CD usw.); dazu, dass FreeSpace / Size Bytewerte vom Typ uint64 sind; dazu, dass DeviceID der Schlüssel ist; sowie zu Beispielabfragen in VBScript / C#, die nach DriveType = 3 filtern.  2 3 4

  10. Microsoft Learn, Installation and configuration for Windows Remote Management. Dazu, dass standardmäßig kein WinRM-Listener konfiguriert ist und WS-Management-Nachrichten daher nicht gesendet oder empfangen werden können; dazu, dass winrm quickconfig den Dienst auf automatischen Start setzt, einen HTTP-/HTTPS-Listener konfiguriert und eine Firewallausnahme einträgt; dazu, dass die Standardports von WinRM 2.0 HTTP 5985 / HTTPS 5986 sind; dazu, dass TrustedHosts so eng wie möglich zu setzen ist, wenn eine gegenseitige Authentifizierung (Kerberos) nicht zustande kommt, etwa in einer Arbeitsgruppe; sowie zum standardmäßigen Sicherheitsdeskriptor (RootSDDL), der den Remotezugriff auf den Listener steuert, und zur zusätzlichen Konfiguration, die nötig ist, um Nicht-Administratoren die Nutzung von WMI-Plug-ins zu erlauben.  2 3 4

  11. Microsoft Learn, System.Management Namespace. Dazu, dass dies der Namensraum ist, der Abfragen an die WMI-Infrastruktur über die ManagementObjectSearcher-Klassenfamilie stellt und Ereignisabonnements über ManagementEventWatcher abwickelt; dazu, dass WqlEventQuery eine Ereignisabfrage im WQL-Format darstellt; sowie dazu, dass ManagementDateTimeConverter Methoden zur Umwandlung zwischen DMTF-Datums-/Zeitangaben und Zeitintervallen sowie DateTime / TimeSpan der CLR bereitstellt.  2 3

  12. Microsoft Learn, Requesting WMI Data on a 64-bit Platform. Dazu, dass bei Providern, die sowohl in 32-Bit- als auch in 64-Bit-Version existieren, standardmäßig der 32-Bit-Provider 32-Bit-Anwendungen (einschließlich Skripten) und der 64-Bit-Provider 64-Bit-Anwendungen bedient; dazu, dass sich die jeweils andere Version über den Kontext-Wert __ProviderArchitecture (32 oder 64) sowie __RequiredArchitecture explizit anfordern beziehungsweise erzwingen lässt (wobei beim Erzwingen einer nicht vorhandenen Version WBEM_E_PROVIDER_LOAD_FAILURE auftritt); sowie zum Beispiel des Registrierungsproviders, bei dem ein 32-Bit-Client Daten von der Seite HKLM\SOFTWARE\Wow6432Node erhält.  2 3

  13. Microsoft Learn, winmgmt. Dazu, dass /verifyrepository von winmgmt.exe eine Konsistenzprüfung des WMI-Repositorys durchführt; dazu, dass /salvagerepository eine Konsistenzprüfung durchführt und bei erkannter Inkonsistenz das Repository neu aufbaut, wobei lesbare Inhalte übernommen werden; dazu, dass /resetrepository das Repository auf den Zustand der ursprünglichen Betriebssysteminstallation zurücksetzt; dazu, dass das Repository als Datenbank aus den Dateien im Repository-Ordner funktioniert; sowie dazu, dass über WMI auftretende Fehler mitunter andere Ursachen im Betriebssystem haben, weshalb das Löschen des Repositorys als erste Maßnahme vermieden werden sollte, da dies zu Schäden am System oder an installierten Anwendungen führen kann.  2 3

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Was ist der Unterschied zwischen WMI und CIM?
CIM ist ein „branchenweiter Standard zur Darstellung von Verwaltungsobjekten wie Systemen und Geräten“, der vom DMTF (Distributed Management Task Force) entwickelt und gepflegt wird. WMI ist Microsofts Implementierung von WBEM, einer Initiative, die diesen Standard nutzt, und ist fest in Windows integriert. Mit anderen Worten: CIM ist die Spezifikation, WMI die Implementierung unter Windows. PowerShells Get-CimInstance und C#s Microsoft.Management.Infrastructure tragen die Bezeichnung „CIM“, weil es sich um APIs handelt, die diesem Standard folgen — die Verbindung geht dabei zur selben WMI-Grundlage. Für die tägliche Entwicklung reicht das Verständnis: „WMI-Klassen (Win32_* usw.) werden über CIM-basierte APIs abgefragt.“
Kann ich Get-WmiObject nicht mehr verwenden?
Unter Windows PowerShell 5.1 funktioniert es weiterhin, aber ab PowerShell 6 (einschließlich der aktuellen PowerShell 7) sind die WMI-v1-Cmdlets Get-WmiObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance und Remove-WmiObject entfernt und lassen sich nicht mehr ausführen. Dieselbe Funktionalität stellt das Modul CimCmdlets bereit (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent usw.). Neue Skripte sollten daher auch dann mit den CIM-Cmdlets geschrieben werden, wenn sie unter 5.1 laufen sollen. So muss bei einer späteren Migration zu PowerShell 7 der WMI-Teil nicht neu geschrieben werden.
Sollte ich in C# System.Management oder Microsoft.Management.Infrastructure verwenden, um auf WMI zuzugreifen?
Beide sind nur unter Windows verfügbar und werden im aktuellen .NET als NuGet-Paket eingebunden. System.Management ist die klassische API, die sich allein durch Übergabe von WQL an einen ManagementObjectSearcher nutzen lässt, und reicht aus, wenn hauptsächlich lokale Informationen abgerufen werden. Es enthält außerdem ManagementDateTimeConverter zur Konvertierung von DMTF-Datumsangaben. Microsoft.Management.Infrastructure (die MI-API) dagegen teilt sich dasselbe Typsystem (CimSession / CimInstance) mit den CIM-Cmdlets von PowerShell und deckt Remoteabfragen über WSMan, asynchrone Methodenvarianten und Ereignisabonnements (Subscribe) einheitlich ab. Wer Remoteabfragen und Überwachung fest in eine Anwendung einbauen will, trifft mit der MI-API die sinnvollere Wahl.
Get-CimInstance verbindet sich nicht mit einem entfernten PC. Was sollte ich prüfen?
Prüfen Sie zuerst, ob auf dem Zielrechner WinRM konfiguriert ist. Ein CIM-Vorgang mit -ComputerName erstellt eine temporäre Sitzung über das WSMan-Protokoll (WinRM) und setzt daher voraus, dass der WinRM-Dienst und ein Listener auf dem Ziel laufen. winrm quickconfig führt die Standardkonfiguration aus (Dienst automatisch starten, Listener erstellen, Firewallausnahme eintragen). Die Standardports sind 5985 für HTTP und 5986 für HTTPS, prüfen Sie also auch die Firewalls entlang des Netzwerkpfads. In einer Arbeitsgruppenumgebung steht keine gegenseitige Authentifizierung über Kerberos zur Verfügung, sodass mitunter eine Eintragung des Ziels in die TrustedHosts-Liste des Clients nötig ist. Für ein Ziel, bei dem WinRM unter keinen Umständen konfiguriert werden kann, lässt sich stattdessen über DCOM verbinden, mit einer über New-CimSessionOption -Protocol Dcom erstellten Option.
Warum wird ein WMI-Datum in einem Format wie „20260801100000.000000+540“ zurückgegeben?
WMI-Datumswerte werden als Zeichenkette im DMTF-Format der CIM-Spezifikation gespeichert (yyyymmddHHMMSS.mmmmmm±UUU, wobei der abschließende Wert den Versatz gegenüber UTC in Minuten angibt). Wird der Rohwert mit dem alten Get-WmiObject oder mit System.Management gelesen, erhält man genau diese Zeichenkette. In C# (System.Management) stellt ManagementDateTimeConverter Methoden zur Umwandlung zwischen dem DMTF-Format und DateTime / TimeSpan bereit — verwenden Sie diese, statt die Zeichenkette selbst zu zerlegen. Bei Abruf über eine CIM-basierte API wie Get-CimInstance oder die MI-API kommen Datumseigenschaften dagegen bereits als DateTime zurück, sodass dieses Problem dort von vornherein nicht auftritt.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog