WMI organizes its classes in a hierarchical namespace. To find useful information, you need to know a Class Name plus the Namespace where it lives.
A Namespace organizes information similar to folders in a filesystem. The top “folder” of the WMI namespace is always called “root”.
Exploring Namespaces
WMI represents namespaces as instances of the class: __Namespace. This class starts with 2 (two) underscores. All internal WMI classes are marked that way.
Finding Child Namespaces of a Namespace
Get-CimInstance -ClassName __Namespace
The result looks similar to this:
Name PSComputerName
---- --------------
mdm
ms_40c
Security
ms_410
power
ms_413
ms_409
TerminalServices
ms_407
WMI namespaces are extensible, so you may see more (or less) namespaces, depending on the kind and type of operating system (client vs. server) and the software you installed.
Get-CimInstance
cannot search recursively through all namespaces. It always searches only one namespace, and if you don’t specify one, it uses the default namespace root/cimv2.
So what you see are the immediate child namespaces of root/cimv2. Some of these serve a special purpose: namespaces that start with ms_ are just language-specific extensions. The number following is the country code, and these namespaces contain localized documentation only.
To find real namespaces with potentially interesting classes in them, exclude any namespace name that starts with *“ms_” followed by at least two numbers.
Excluding Localization Namespaces
Get-CimInstance -ClassName __Namespace |
Where-Object Name -NotMatch '^ms_\d{2}'
The result looks similar to this:
Name PSComputerName
---- --------------
mdm
Security
power
TerminalServices
Apparently, the namespace root/cimv2 has four child namespaces.
Listing All Available Namespaces
To find all namespaces, you need to start the search at the top namespace root and then search recursively through all child namespaces.
Listing all namespaces
Since recursion is hard to debug and has the risk of running into out-of-memory errors when nesting levels are too deep, I am using a better alternative: a Queue.
Some namespaces are protected, so in order to get a full list, make sure you run below code with Administrator privileges.
# create a new queue
$namespaces = [System.Collections.Queue]::new()
# add an initial namespace to the queue
# any namespace in the queue will later be processed
$namespaces.Enqueue('root')
# process all elements on the queue until all are taken
While ($namespaces.Count -gt 0 -and ($current = $namespaces.Dequeue()))
{
# find child namespaces
Get-CimInstance -Namespace $current -ClassName __Namespace -ErrorAction Ignore |
# ignore localization namespaces
Where-Object Name -NotMatch '^ms_\d{2}' |
ForEach-Object {
# construct the full namespace name
$childnamespace = '{0}\{1}' -f $current, $_.Name
# add namespace to queue
$namespaces.Enqueue($childnamespace)
}
# output current namespace
$current
}
The result on an average Windows 10 client looks similar to this:
root
root\subscription
root\DEFAULT
root\CIMV2
root\msdtc
root\Cli
root\Intel_ME
root\SECURITY
root\SecurityCenter2
root\RSOP
root\PEH
root\StandardCimv2
root\WMI
root\MSPS
root\directory
root\Policy
root\Interop
root\Hardware
root\ServiceModel
root\SecurityCenter
root\Microsoft
root\Appv
root\dcim
root\CIMV2\mdm
root\CIMV2\Security
root\CIMV2\power
root\CIMV2\TerminalServices
root\RSOP\User
root\RSOP\Computer
root\StandardCimv2\embedded
root\directory\LDAP
root\Microsoft\HomeNet
root\Microsoft\protectionManagement
root\Microsoft\Windows
root\Microsoft\SecurityClient
root\Microsoft\Uev
root\dcim\sysman
root\CIMV2\mdm\dmmap
root\CIMV2\Security\MicrosoftTpm
root\CIMV2\Security\MicrosoftVolumeEncryption
root\Microsoft\Windows\RemoteAccess
root\Microsoft\Windows\Dns
root\Microsoft\Windows\Powershellv3
root\Microsoft\Windows\Hgs
root\Microsoft\Windows\WindowsUpdate
root\Microsoft\Windows\DeviceGuard
root\Microsoft\Windows\TaskScheduler
root\Microsoft\Windows\DesiredStateConfigurationProxy
root\Microsoft\Windows\SmbWitness
root\Microsoft\Windows\Wdac
root\Microsoft\Windows\StorageReplica
root\Microsoft\Windows\winrm
root\Microsoft\Windows\AppBackgroundTask
root\Microsoft\Windows\DHCP
root\Microsoft\Windows\PS_MMAgent
root\Microsoft\Windows\Storage
root\Microsoft\Windows\HardwareManagement
root\Microsoft\Windows\SMB
root\Microsoft\Windows\EventTracingManagement
root\Microsoft\Windows\DesiredStateConfiguration
root\Microsoft\Windows\CI
root\Microsoft\Windows\dfsn
root\Microsoft\Windows\Defender
root\dcim\sysman\biosattributes
root\dcim\sysman\wmisecurity
root\Microsoft\Windows\RemoteAccess\Client
root\Microsoft\Windows\Storage\PT
root\Microsoft\Windows\Storage\Providers_v2
root\Microsoft\Windows\Storage\PT\Alt
Listing Classes in a Namespace
Now that you know the names of the available namespaces, Get-CimClass
can list the valid class names inside of each.
List class names for namespace root\cimv2
# list all classes that live in namespace "root\cimv2"...
Get-CimClass -Namespace 'root\cimv2' |
# take only the class name...
Select-Object -ExpandProperty CimClassName |
# and sort the output:
Sort-Object
The result is a huge list: on an average Windows 10 client, the namespace root/cimv2 contains 1,200 classes.
Identifying Useful Classes
Because there are so many WMI classes, it is important to define a strategy to identify potentially useful classes. The class name prefix can give a clue:
Prefix | Count | Description |
---|---|---|
__ | 53 | internal WMI class used to organize WMI |
CIM | 286 | Original class definitions |
Win32 | 749 | Extended Microsoft implementations that inherit from a CIM class |
MSFT | 102 | Unique Microsoft class that does not inherit from a CIM class |
There are a few class names that do not use prefixes. Add them to the “potentially interesting class” pile.
By excluding any class name that either starts with two underscores or with CIM_, you can eliminate a significant portion.
Exclude “Link” Classes
Classes can have relationships to each other, and these links are defined yet by other classes, similar to a database join. Typically, classes that just link two other classes have at most 3 propertes. Any of these classes can be excluded.
Exclude Performance Counters
Every performance counter has its own WMI class, so if you are not explicitly trying to read performance counter values, exclude any classname that starts with Win32_Perf.
Exclude Plug&Play Classes
Another rather large group of classes describes plug&play functionality and starts with Win32_PnP. You can safely ignore these classes in most cases because the actual plug&play devices and most of the information about them surfaces in other more specific classes.
Listing potentially useful classes in namespace cimv2
# get all classes from namespace "root/cimv2"...
Get-CimClass -Namespace 'root\cimv2' |
# exclude classes that start with __/CIM/Win32_PnP/Win32_Perf
Where-Object CimClassName -NotMatch '^(__|CIM_|Win32_PnP|Win32_Perf)' |
# exclude classes with less than 4 properties...
Where-Object { $_.CimClassProperties.Count -gt 3 } |
# return just the class name...
Select-Object -ExpandProperty CimClassName |
# sort results:
Sort-Object
This reduces the class count from 1,200 to 319 classes.