Using WMI/CIM from C# and PowerShell — A Practical Guide to Hardware Info Retrieval, Process Monitoring, and Remote Queries
· Go Komura · Windows, C#, .NET, PowerShell, WMI, CIM, Business Applications, Windows Development
“I want to show the PC’s serial number and model name in a business application’s screen.” “I want to monitor a server’s free disk space and raise a warning.” “I want to detect when a particular process starts.” “I want to gather the status of PCs in a remote location in one place.” — these kinds of requirements come up all the time when building Windows business applications and management tools. And the standard answer to them is WMI (Windows Management Instrumentation), or, to use its standard name, CIM (Common Information Model).
What makes this tricky is that information about WMI is a mix of old and new. Search for it and you will find ten-year-old articles using Get-WmiObject sitting alongside articles using Get-CimInstance, and on the C# side there are two separate lineages, System.Management and Microsoft.Management.Infrastructure. It is hard to tell which is the current way of writing things and which “still works but is not what you should choose for new code.” In fact, Get-WmiObject does not exist in PowerShell 7 at all, and this suddenly surfaces when migrating an in-house script that was written for 5.1.
This article is aimed at C#/PowerShell developers implementing hardware information retrieval, process monitoring, and remote PC queries in business applications. It works from a minimal understanding of WMI/CIM’s structure through PowerShell’s CIM cmdlets, the two C# APIs, frequently used recipe examples, pitfalls around performance, permissions, and 64-bit, and finally how to judge “situations where you should not use WMI” — all organised from primary sources current as of August 2026.
1. The Bottom Line First
- CIM is the industry-standard model for management information defined by the DMTF, and WMI is Microsoft’s implementation of it. The “CIM” family of APIs in PowerShell and C# are the current generation of APIs that follow this standard, and they connect to the same underlying WMI.1
- In PowerShell, the current generation is the CIM cmdlets (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent). The old WMI cmdlets (Get-WmiObject and four others) have been removed from PowerShell 6 onward and do not run in PowerShell 7.2
- The default namespace is root/CIMV2, and day-to-day queries are basically a matter of narrowing down the Win32_* classes there with WQL.3
- Remote queries default to WSMan (WinRM). Specifying
-ComputerNamecreates a temporary WSMan session. If you are going to query the same target repeatedly, reusing a CIM session (New-CimSession) is the established practice for performance, and for older targets where WinRM cannot be configured, there is a DCOM protocol option.34 - C# has two lineages: System.Management (ManagementObjectSearcher) and Microsoft.Management.Infrastructure (CimSession). Both are Windows-only, and on current .NET you bring them in via NuGet. If you are building remote queries or monitoring into a real product, the MI API — which shares the same type system as the CIM cmdlets — is the better fit.56
- Detect process launches with an event subscription, not polling. Subscribing to
Win32_ProcessStartTracemust be run with administrator rights.78 - Do not use
SELECT *out of habit. Narrowing what is transferred with-Filter/-Property/-KeyOnlyprevents about half of WMI’s performance problems.3 - WMI is not a universal solution. For high-frequency performance monitoring, reading and writing your own application’s settings, or one-off OS function calls, performance counters, the registry, the Win32 API, or dedicated cmdlets are a better fit (see the decision table in Section 8).
2. What WMI/CIM Is — Standard vs. Implementation, Namespaces, Classes, and WQL
First, let’s sort out the terminology once and for all.
| Term | What it is |
|---|---|
| CIM (Common Information Model) | The industry-standard model for representing management targets such as systems, applications, networks, and devices. Defined and maintained by the DMTF (Distributed Management Task Force)1 |
| WBEM (Web-Based Enterprise Management) | An industry initiative to create standard technologies for accessing management information in enterprise environments1 |
| WMI | Microsoft’s implementation of WBEM. It represents management targets using the CIM standard and is built into Windows1 |
| MI (Windows Management Infrastructure) | The next-generation version of WMI. Fully compatible with legacy WMI, and most new providers are written in MI1 |
As a developer, there are four structural pieces worth understanding.
- Namespace: a hierarchy that groups classes together. For day-to-day queries you will almost always use root/CIMV2, which is also the default for the CIM cmdlets.3 Others include
root\default(the registry provider, among others). - Class: a type representing a management target, such as
Win32_ComputerSystem(the computer itself),Win32_LogicalDisk(a logical drive), orWin32_Process(a process). Windows-specific classes that inherit from CIM-standard classes (such asCIM_LogicalDisk) carry theWin32_prefix.9 - Provider: the component that supplies the substance of a class. When you query it, the provider asks the OS on the spot and builds the values.
- WQL: an SQL-like query language. As in
SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto', it treats a class like a table and filters it down. WQL is also the default query language for the CIM cmdlets.3
“Reading OS and hardware information through a unified set of classes and a query language” — that is the value WMI provides. Conversely, writing and control operations are limited to the subset of classes that have methods you can call via Invoke-CimMethod; it is not a mechanism that can do absolutely anything.
3. Usage from PowerShell — CIM Cmdlets Are Current, WMI Cmdlets Are Removed
3.1. The basics: Get-CimInstance
# By class name (default namespace root/CIMV2)
Get-CimInstance -ClassName Win32_OperatingSystem
# Write only the WHERE clause content in -Filter (do not write the WHERE keyword itself)
Get-CimInstance -ClassName Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'"
# Retrieve only the properties you need, to reduce the amount transferred
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, CreationDate
# Use -Query if you want to write raw WQL
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE 'p%'"
-Filter is exactly the WHERE clause of WQL, and -Property restricts which columns are retrieved.3 The return value is a CimInstance object, and date properties (such as CreationDate or LastBootUpTime) come back already converted to DateTime. Unlike the old Get-WmiObject, the retrieved object does not carry methods directly, so method calls are made by piping into Invoke-CimMethod.
# Calling a method on an instance: get each process's owner
Get-CimInstance -ClassName Win32_Process -Filter "Name = 'notepad.exe'" |
Invoke-CimMethod -MethodName GetOwner
# Calling a class's static method: launch a process
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = 'notepad.exe' }
# Inspect the class definition (properties and methods)
Get-CimClass -ClassName Win32_Process
3.2. Migration table from the old WMI cmdlets
From PowerShell 6 onward (including the current PowerShell 7), the following WMI v1 cmdlets have been removed. The same functionality is provided by the CimCmdlets module (WMI v2).2
| Old (up to Windows PowerShell 5.1) | Current (CIM cmdlets) | Notes |
|---|---|---|
Get-WmiObject |
Get-CimInstance |
The -Filter / -Query concepts are the same |
Get-WmiObject -List |
Get-CimClass |
Discovering and inspecting class definitions |
Invoke-WmiMethod |
Invoke-CimMethod |
Arguments are passed as a hashtable via -Arguments @{ } |
Register-WmiEvent |
Register-CimIndicationEvent |
Event subscription (Section 6.3) |
Set-WmiInstance |
Set-CimInstance |
Changing writable properties |
Remove-WmiObject |
Remove-CimInstance |
Deleting an instance |
The CIM cmdlets also work under Windows PowerShell 5.1, so anything you write from now on should be written using CIM even if it will run under 5.1 — that way you leave no migration cost behind. For the full picture of coexisting with and migrating between 5.1 and 7, see “The Differences Between Windows PowerShell 5.1 and PowerShell 7”.
4. Remote Queries — CIM Sessions (WSMan by Default) and the DCOM Option
If you do not specify a target, the CIM cmdlets connect to the local WMI over COM; if you specify -ComputerName, they create a temporary session over the WSMan (WinRM) protocol to connect. When you are going to perform multiple operations against the same computer, creating a CIM session and reusing it is better for performance.3
# For a one-off query, use -ComputerName (a temporary session is created each time)
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName Server01, Server02
# For repeated queries, reuse a CIM session
$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
For targets you cannot reach over WSMan — such as older machines where WinRM cannot be configured — you can choose the DCOM protocol instead.4
$dcom = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName OldServer -SessionOption $dcom
The prerequisites for a remote query are as follows.
- WinRM must be configured on the target.
winrm quickconfigsets the service to start automatically, creates an HTTP listener (default port 5985), and registers a firewall exception, all in one go.10 If you want to connect over HTTPS (default port 5986), this alone is not enough — you need to prepare a server certificate and separately configure an HTTPS listener with something likewinrm quickconfig -transport:https.10 - The relevant ports must be open on any firewalls along the path. The practical work of designing and registering inbound rules is covered in the article “Windows Firewall and Business Applications.”
- Authentication. In a domain environment, Kerberos provides mutual authentication. In a workgroup, Kerberos is not available, so you may need to register the target in the client’s
TrustedHostslist. Keep that list as narrow as possible.10 - Permissions. Under the default configuration, remote WMI queries and operations are basically performed with an account that belongs to the target’s administrators group. To open this up to ordinary users, you need to configure access permissions on both WinRM and the WMI namespace.10
- Note that DCOM has no fixed listening port (it uses dynamic RPC ports), which makes it harder to design across a firewall boundary. It is safest to assume WSMan as the default for anything you build from now on.
5. Usage from C# — System.Management vs. Microsoft.Management.Infrastructure
There are two lineages of API for using WMI from C#. Both are Windows-only.
| System.Management | Microsoft.Management.Infrastructure (MI API) | |
|---|---|---|
| Bringing it in | Included by default in .NET Framework. On current .NET, the NuGet package System.Management5 | The NuGet package Microsoft.Management.Infrastructure6 |
| Entry-point class | ManagementObjectSearcher (pass WQL to query)5 |
CimSession (Create → QueryInstances / InvokeMethod / Subscribe)6 |
| Type system | ManagementObject / ManagementEventWatcher11 |
CimInstance / CimSession — the same types as the CIM cmdlets3 |
| Remote access | DCOM-based | WSMan (CIM session) based. Asynchronous variants (*Async) are available6 |
| Best suited to | Local information retrieval. Maintaining existing code assets | Building in remote queries and monitoring. Designs that pair with PowerShell |
5.1. System.Management: the basics of ManagementObjectSearcher
You pass WQL as a string and receive a result collection via Get().5
// NuGet: System.Management (Windows-only)
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"]} free {freeGb:F1} GB / total {sizeGb:F1} GB");
}
Properties are returned as object through an indexer, so you need to check the class documentation for the CIM type (in this example, FreeSpace / Size are uint649) and cast accordingly. Assuming it is int and casting on that assumption, resulting in an InvalidCastException, is the classic first stumbling block here.
5.2. MI API: the basics of CimSession
CimSession handles local and remote access in the same shape. It covers enumeration, querying, method calls, event subscription, and asynchronous variants all in one place.6
// NuGet: Microsoft.Management.Infrastructure (Windows-only)
using Microsoft.Management.Infrastructure;
// CimSession.Create(null) for local, or pass a computer name for remote
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} free {free / 1024.0 / 1024 / 1024:F1} GB");
}
Because it works with the same CimInstance that PowerShell’s CIM cmdlets return, a development flow of “try it in PowerShell first, then transcribe it into C#” connects naturally. If you are designing the C#-and-PowerShell integration itself, also see “How to Run PowerShell from C# (CSharp) and Receive the Results as Objects”.
6. Frequently Used Recipes
6.1. Quick reference for common classes
| Information you want | Class | Main properties |
|---|---|---|
| Manufacturer / model name | Win32_ComputerSystem |
Manufacturer, Model |
| Chassis serial number | Win32_BIOS |
SerialNumber |
| OS version / boot time | Win32_OperatingSystem |
Caption, Version, LastBootUpTime |
| Free disk space | Win32_LogicalDisk |
DeviceID, FreeSpace, Size, DriveType9 |
| Service state | Win32_Service |
Name, State, StartMode |
| Process list | Win32_Process |
Name, ProcessId, CommandLine |
6.2. The asset-management staple: serial number, model name, and disk free space
# Model information and serial number (for reconciling against a PC asset ledger)
$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
}
# Free space on local disks (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 represents “local disk”, excluding removable (2), network drives (4), and CD drives (5).9 For monitoring, simply rolling this script out to each server via a CIM session gives you the foundation for agentless disk monitoring.
6.3. Detecting process launches — event subscription
Rather than “periodically fetching Win32_Process by polling and diffing it”, use an event subscription. The simplest way to catch a process launch is to subscribe to Win32_ProcessStartTrace (an event class from the kernel trace provider, with properties such as ProcessName / ProcessID / ParentProcessID8).
# Run this from an elevated (administrator) PowerShell session
$action = {
$name = $Event.SourceEventArgs.NewEvent.ProcessName
$id = $Event.SourceEventArgs.NewEvent.ProcessID
Write-Host "Process started: $name (PID=$id)"
}
Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace `
-SourceIdentifier ProcessStarted -Action $action
The subscription stays live for as long as the PowerShell session that registered it is alive, and -Action runs every time a process starts. Be careful not to run the unsubscribe command right after this in the same batch — doing so just makes the subscription disappear before monitoring even begins. Only run the unsubscribe step when you are finished monitoring.
# When you are done monitoring: remove the subscription
Unregister-Event -SourceIdentifier ProcessStarted
Register-CimIndicationEvent registers a subscription by class name or by a WQL event query, and the -Action script block runs each time an event arrives.7 Subscribing to this class requires administrator rights.7 Who can receive the event is controlled by the event class’s security descriptor, and an ordinary user without elevated rights will be denied access.8
Another option is the generic instance-creation event (__InstanceCreationEvent), which can be used with any class. This works by having WMI poll at the interval you specify with WITHIN and turn the resulting diff into an event, so you have to decide the trade-off between detection interval and load yourself.
# Monitor for new Win32_Process instances by polling every 5 seconds
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent -Query $query -SourceIdentifier ProcPoll -Action {
Write-Host "Started: $($Event.SourceEventArgs.NewEvent.TargetInstance.Name)"
}
In C# (System.Management), ManagementEventWatcher plays the same role.11
using System.Management;
// From a process running as administrator
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($"Process started: {name} (PID={pid})");
};
watcher.Start();
// Don't forget watcher.Stop() and Dispose when monitoring ends
If you are building this into a long-running monitoring component, make sure your design also covers re-registering the subscription when it drops (on service restart or on error). The design considerations for “checking and displaying status”, including device monitoring, are covered in “Best Practices for Checking and Displaying External Device State”.
7. Pitfalls — Performance, Permissions, 64-bit, the Repository, and Dates
7.1. SELECT * and polling too aggressively
A WMI query is “a provider building the values on the spot” — it is not free. There are two classic anti-patterns.
- Using
SELECT *out of habit. Retrieving every property of every row ofWin32_Processinflates the work the provider does and the network transfer (when remote) accordingly. Narrow rows with-Filter, narrow columns with-Property, and use-KeyOnlyif all you need are keys for a follow-up operation. All of these are official, purpose-built means “to reduce the size of the objects and the network traffic.”3 - Short-interval polling. A design such as “
Get-CimInstance Win32_Processevery second” should be replaced with the event subscription approach from Section 6.3. Even if you must use the polling style (WITHIN), widen the interval to whatever is genuinely sufficient for the requirement.
Also, repeating -ComputerName one target at a time against remote machines is wasteful, because a temporary session is created for every single query — switch to reusing a CIM session for multiple operations.3
7.2. Permissions for event subscriptions
As covered in Section 6.3, subscribing to the Win32_ProcessStartTrace family requires administrator rights.7 “It worked on the development machine (running as administrator), but monitoring doesn’t work in the customer’s ordinary-user environment” is a classic failure mode, right up there with the firewall notification dialog. If you are building monitoring into a business application that runs as an ordinary user, consider splitting the monitoring part out into a Windows service (running as LocalSystem, for example) and connecting it to the main application via inter-process communication.
7.3. 32-bit vs. 64-bit and providers
On 64-bit Windows, some providers exist as both a 32-bit and a 64-bit version, and by default the version matching the caller’s bitness answers the request.12 The classic example is the registry provider (StdRegProv) under root\default: reading from a 32-bit application returns values from the Wow6432Node side (the 32-bit view).12 If “the registry value read via WMI doesn’t match what regedit shows”, this is the first thing to suspect. If you need the other view, you can explicitly request it by setting __ProviderArchitecture (and, if you want to force it, __RequiredArchitecture) in the connection context.12 The overall picture of bitness issues is also covered in “Safely Calling Win32 APIs from C# — A Practical P/Invoke Guide”.
7.4. Symptoms and remedies for a corrupted WMI repository
WMI’s class definitions are stored in a repository (not a single file — the files inside the Repository folder together function as a database13). When it becomes inconsistent, errors such as “a class that should exist cannot be found” or “the namespace is invalid” start appearing, even though nothing changed on the application side. Use winmgmt.exe to diagnose and repair it.13
rem Consistency check (result "inconsistent" means there is a problem)
winmgmt /verifyrepository
rem Consistency check, and rebuild if there is a problem (readable content is merged)
winmgmt /salvagerepository
The important thing is not to make deleting or resetting the repository your first move. Errors surfaced through WMI can originate elsewhere in the OS, and Microsoft itself states plainly that deleting the repository as a first response “can cause damage to the system or to installed applications.”13 Follow the order: check with /verifyrepository, then repair with /salvagerepository.
7.5. Converting DMTF date format
WMI dates are stored as strings in the DMTF format defined by the CIM specification: yyyymmddHHMMSS.mmmmmm±UUU (the trailing value is the offset from UTC in minutes — for example, 20260801100000.000000+540). Do not slice and splice the raw value with string processing; use the conversion API instead.
- C# (System.Management):
ManagementDateTimeConverterprovides conversion between the DMTF format andDateTime/TimeSpan.11 - CIM-family APIs (Get-CimInstance / MI API): date properties come back already converted to
DateTime, so you never run into this problem in the first place.(Get-CimInstance Win32_OperatingSystem).LastBootUpTimecan be used directly as aDateTimein calculations.
8. Situations Where You Should Not Use WMI — A Decision Table
WMI is excellent as a “unified read interface”, but it is not always the optimal choice. Here is a practical rule of thumb for choosing between tools.
| What you want to do | The right tool | Why not WMI |
|---|---|---|
| Retrieving hardware information and OS configuration, agentless remote queries | WMI/CIM | This is exactly WMI’s home turf — more unified than hitting dedicated APIs one by one |
| Reading and writing your own application’s settings | Reading the registry directly (Microsoft.Win32.Registry) or configuration files |
Registry access through WMI is a roundabout route, and it also inherits the bitness issue from Section 7.3 |
| High-frequency, continuous performance monitoring such as CPU usage | Performance counters (System.Diagnostics.PerformanceCounter, etc.) |
Counters are purpose-built for exactly this. Short-interval WMI polling loses on both load and accuracy |
| A one-off OS function call, or processing that needs low latency | The Win32 API (P/Invoke) | WMI carries the overhead of going through COM/a provider |
| Enumerating and manipulating local processes when your own process’s permissions are sufficient | System.Diagnostics.Process |
Self-contained in the standard library, with fewer dependencies |
| Configuring Windows management features such as the firewall or networking | Dedicated CIM-based cmdlets such as Get-NetFirewallRule |
A cmdlet set built and maintained for a specific purpose is more accurate and safer than hunting through raw WMI classes |
| Detecting file or folder changes | FileSystemWatcher |
Don’t bring WMI into territory that already has a dedicated API |
The rule of thumb is simple: use the dedicated mechanism where one exists, and reserve WMI/CIM for cross-cutting queries and remote queries. The Get-NetFirewallRule example in the last row is, internally, a cmdlet set built on top of CIM — a case of “getting the benefit of WMI/CIM without touching it directly.”
9. Summary
- CIM is the DMTF’s industry standard, and WMI is Microsoft’s implementation of it. Both PowerShell’s CIM cmdlets and C#’s MI API are current-generation entry points that follow this standard.
- In PowerShell, Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent are current. Get-WmiObject and the other WMI cmdlets do not exist in PowerShell 7, so write new scripts on the CIM side even if they target 5.1.
- Remote queries default to WSMan (WinRM), and multiple operations should reuse a CIM session. For a target where WinRM is not configured, DCOM is an available fallback.
- In C#, choose between System.Management (handy, local-oriented) and Microsoft.Management.Infrastructure (remote- and monitoring-oriented, sharing the CIM cmdlets’ type system). Both are Windows-only NuGet packages.
- Monitor processes through event subscription, not polling. Subscribing to Win32_ProcessStartTrace requires administrator rights.
- Avoid SELECT * and short-interval polling — narrow things down with -Filter / -Property / -KeyOnly. Remember that a query from a 32-bit process is served by the 32-bit provider, that DMTF dates need the conversion API, and that a corrupted repository should be handled in the order verify → salvage, not deletion.
- Do not bring WMI into territory that already has a dedicated mechanism (settings, performance counters, one-off API calls) — reserve WMI/CIM for cross-cutting queries and remote queries. That one line sums up where it belongs.
Related Articles
- How to Run PowerShell from C# (CSharp) and Receive the Results as Objects
- Practical PowerShell Command Recipes — Growing the Small Tools You Use Every Day
- The Differences Between Windows PowerShell 5.1 and PowerShell 7 — A Practical Guide to Migrating In-House Scripts
- Best Practices for Checking and Displaying External Device State - Designing Beyond a Single ‘Connected’
- Safely Calling Win32 APIs from C# — A Practical P/Invoke Guide (DllImport / LibraryImport / CsWin32)
- What Is the TPM in Windows? — An Illustrated Guide to the “Safe That Never Lets Keys Out” and Measured Boot
Related Consulting Areas
KomuraSoft LLC handles building hardware information retrieval, process monitoring, and remote PC queries with WMI/CIM into business applications, migrating in-house scripts based on Get-WmiObject to the CIM cmdlets, and investigating the kind of problem where “it works on the development machine but fails with a permissions error at the customer site.” We can support you through the whole path from prototyping in PowerShell to a full C# implementation.
- Windows Application Development
- Bug Investigation and Root Cause Analysis
- Technical Consulting and Design Review
- Contact Us
References
-
Microsoft Learn, About WMI. On WMI being Microsoft’s implementation of WBEM (an industry initiative to develop standard technologies for accessing management information in enterprise environments), representing management targets using the industry-standard CIM (Common Information Model), developed and maintained by the DMTF (Distributed Management Task Force); on the next-generation MI (Windows Management Infrastructure) being fully compatible with legacy WMI; and on remote WMI connections using DCOM, with WS-Management-based WinRM as an alternative. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. On the WMI v1 cmdlets (Register-WmiEvent / Set-WmiInstance / Invoke-WmiMethod / Get-WmiObject / Remove-WmiObject) having been removed from PowerShell, and on the CimCmdlets module (WMI v2) cmdlets providing the same functionality with new features and redesigned syntax. ↩ ↩2
-
Microsoft Learn, Get-CimInstance (CimCmdlets). On connecting to the local WMI over a COM session when neither ComputerName nor CimSession is specified, and creating a temporary session over the WsMan protocol when -ComputerName is specified; on connecting via a CIM session being recommended for performance when performing multiple operations against the same computer; on -Filter being a WQL/CQL where clause that does not include the WHERE keyword; on -Property and -KeyOnly reducing object size and network traffic; on the default namespace being root/CIMV2 and the default query language (-QueryDialect) being WQL; on the output being Microsoft.Management.Infrastructure.CimInstance; on an example of calling GetOwner in combination with Invoke-CimMethod; and on the cmdlet being Windows-only. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Microsoft Learn, New-CimSessionOption (CimCmdlets). On CIM session options having two parameter sets, for WsMan and for DCOM; on -Protocol accepting Dcom / Default / Wsman; on an example of passing an option created with New-CimSessionOption -Protocol Dcom into New-CimSession’s -SessionOption to create a DCOM CIM session; and on the default impersonation level for a DCOM session being Impersonate. ↩ ↩2
-
Microsoft Learn, ManagementObjectSearcher Class (System.Management). On this being the most common entry-point class for retrieving management information, retrieving a collection of management objects based on a specified WQL query; on it accepting an ObjectQuery and a ManagementScope (the WMI namespace) and returning a ManagementObjectCollection via Get(); and on System.Management.dll being provided as the NuGet package System.Management. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, CimSession Class (Microsoft.Management.Infrastructure). On Microsoft.Management.Infrastructure.dll being provided as the NuGet package Microsoft.Management.Infrastructure; on creating a session via Create(computerName); on executing a query via QueryInstances(namespace, queryDialect, query); and on it providing EnumerateInstances / GetInstance / InvokeMethod / Subscribe together with asynchronous (*Async) variants of each, while implementing IDisposable. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). On subscribing to an indication (event) by class name or query expression and naming the subscription with -SourceIdentifier; on an example of subscribing to Win32_ProcessStartTrace, with a note that it requires running PowerShell as administrator; on an example of referencing ProcessName / ProcessId from $Event.SourceEventArgs.NewEvent inside the -Action script block; on connecting via a temporary WsMan session when -ComputerName is specified, and locally over COM when it is not; and on using Unregister-Event to remove a subscription. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Win32_ProcessStartTrace class. On this being an event class indicating the start of a new process, with properties including ProcessName / ProcessID / ParentProcessID / SessionID / Sid; on the SECURITY_DESCRIPTOR property being the descriptor the event provider uses to determine which users can receive the event; and on the namespace being Root\CIMV2, provided by the kernel trace provider (Krnlprov.dll). ↩ ↩2 ↩3
-
Microsoft Learn, Win32_LogicalDisk class. On Win32_LogicalDisk being a class derived from CIM_LogicalDisk that represents a local storage device; on the values of DriveType (2 = removable, 3 = local disk, 4 = network drive, 5 = CD, and so on); on FreeSpace / Size being uint64 byte values; on DeviceID being the key; and on example VBScript / C# queries filtering by DriveType = 3. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Installation and configuration for Windows Remote Management. On a WinRM listener not being configured by default, meaning WS-Management messages cannot be sent or received; on winrm quickconfig setting the service to start automatically, configuring an HTTP/HTTPS listener, and registering a firewall exception; on WinRM 2.0’s default ports being HTTP 5985 / HTTPS 5986; on setting TrustedHosts as narrowly as possible when mutual authentication (Kerberos) cannot be established, such as in a workgroup; and on the default security descriptor (RootSDDL) controlling remote access to the listener, plus the additional configuration required to allow non-administrator users to use WMI plug-ins. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, System.Management Namespace. On this being the namespace that queries the WMI infrastructure through the ManagementObjectSearcher family of classes, and handles event subscription through ManagementEventWatcher; on WqlEventQuery representing an event query in WQL form; and on ManagementDateTimeConverter providing methods to convert between DMTF date/time and time-interval representations and the CLR’s DateTime / TimeSpan. ↩ ↩2 ↩3
-
Microsoft Learn, Requesting WMI Data on a 64-bit Platform. On, where a provider exists in both 32-bit and 64-bit versions, the 32-bit provider by default answering 32-bit applications (including scripts) and the 64-bit provider answering 64-bit applications; on being able to request or force the non-default provider version via the context’s __ProviderArchitecture (32 or 64) and __RequiredArchitecture (with WBEM_E_PROVIDER_LOAD_FAILURE occurring if forcing to a version that is not present); and on the registry-provider example where a 32-bit client receives data from the HKLM\SOFTWARE\Wow6432Node side. ↩ ↩2 ↩3
-
Microsoft Learn, winmgmt. On winmgmt.exe’s /verifyrepository performing a consistency check of the WMI repository; on /salvagerepository performing a consistency check and, if inconsistency is detected, rebuilding the repository while merging in whatever content could be read; on /resetrepository restoring the repository to its state at initial OS installation; on the repository functioning as a database made up of the files inside the Repository folder; and on WMI-surfaced errors sometimes originating elsewhere in the OS, such that deleting the repository as a first response should be avoided because it can cause damage to the system or to installed applications. ↩ ↩2 ↩3
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Windows App Outsourcing and Contract Development: What to Sort Out Before You Ask
Before commissioning Windows app outsourcing or contract development, here is how to sort out existing software modification, device inte...
Practical Multithreading Best Practices: .NET Edition — What to Decide Before You Add More Threads
A practical rundown of the design rules that keep multithreaded .NET/C# code from occasionally crashing or hanging: ride on Task instead ...
Japanese Era Dates, Public Holidays, and Closing-Date Processing in Business Apps — Era-Resilient Design, JapaneseCalendar, and Business-Day Calculations in Practice
A report that must show '令和8年' in the Japanese era, business-day calculations that exclude public holidays, payment due on the last busin...
Preventing Multiple Instances of a Windows App — Named Mutexes and Activating the Existing Window on a Second Launch
This article organizes the classic requirement for business Windows apps — 'don't let the same app launch twice' — around a named Mutex. ...
How to Run PowerShell from C# (CSharp) and Receive the Results as Objects
How to launch PowerShell from C# and receive results as PSObject rather than strings — a practical walkthrough of the PowerShell SDK, Add...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Frequently Asked Questions
Common questions about the topic of this article.
- What is the difference between WMI and CIM?
- CIM is the "industry-standard model for representing management targets such as systems and devices", defined and maintained by the DMTF (Distributed Management Task Force). WMI is Microsoft's implementation of WBEM, an initiative that uses that standard, and it is built into Windows. In other words, CIM is the specification and WMI is the implementation on Windows. PowerShell's Get-CimInstance and C#'s Microsoft.Management.Infrastructure call themselves "CIM" because they are APIs that follow this standard, but they connect to the same underlying WMI. For day-to-day development, it is enough to understand it as "querying WMI classes (Win32_* and so on) through CIM-family APIs".
- Can I no longer use Get-WmiObject?
- It still works in Windows PowerShell 5.1, but from PowerShell 6 onward (including the current PowerShell 7), the WMI v1 cmdlets — Get-WmiObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance, and Remove-WmiObject — have been removed and cannot be run. The same functionality is provided by the CimCmdlets module (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent, and so on). When writing new scripts, it is safer to write them with the CIM cmdlets even if they will run under 5.1. Doing so means you never have to rewrite the WMI portion when you later migrate to PowerShell 7.
- Should I use System.Management or Microsoft.Management.Infrastructure to access WMI from C#?
- Both are Windows-only, and from current .NET you bring them in as NuGet packages. System.Management is the classic API, usable just by passing WQL to a ManagementObjectSearcher, and it is enough on its own if you are mainly retrieving local information. It also includes ManagementDateTimeConverter, which converts DMTF dates. Microsoft.Management.Infrastructure (the MI API), on the other hand, shares the same type system (CimSession / CimInstance) as PowerShell's CIM cmdlets, and it handles remote queries over WSMan, asynchronous method variants, and event subscription (Subscribe) all in a consistent way. If you are building remote PC queries and monitoring into a real product, choosing the MI API is the sensible call.
- Get-CimInstance won't connect to a remote PC. What should I check?
- First check whether WinRM is configured on the target machine. A CIM operation that specifies -ComputerName creates a temporary session over the WSMan (WinRM) protocol, so it assumes the WinRM service and a listener are running on the target. winrm quickconfig performs the default configuration (starting the service, creating a listener, and adding a firewall exception). The default ports are 5985 for HTTP and 5986 for HTTPS, so also check any firewalls along the path. In a workgroup environment, mutual authentication via Kerberos is not available, so you may need to register the target in the client's TrustedHosts list. For a target where you absolutely cannot configure WinRM, you can instead connect over DCOM using an option created with New-CimSessionOption -Protocol Dcom.
- Why does a WMI date come back in a format like "20260801100000.000000+540"?
- WMI dates are stored in the string format defined by the DMTF CIM specification (yyyymmddHHMMSS.mmmmmm±UUU, where the trailing value is the offset from UTC in minutes). If you read the raw value with the old Get-WmiObject or with System.Management, you get this string as-is. In C# (System.Management), ManagementDateTimeConverter provides methods to convert between the DMTF format and DateTime / TimeSpan, so use those rather than slicing the string yourself. Note that when you retrieve data through a CIM-family API such as Get-CimInstance, date properties are already returned converted to DateTime, so you never run into this problem in the first place.