Leveraging WMI (Part 5)

by Apr 26, 2022

WMI classes are organized in so-called namespaces that start at “root” and work like a directory structure. The default namespace is rootcimv2, and when you do not specify a namespace, you can only see the WMI classes located in the default namespace. This is what we have been using in the past parts of this series.

There are many more namespaces with many additional WMI classes, some of which can be highly useful. Before we explore this part of WMI, be advised that you are going to tap into sparsely documented areas of Windows that are not necessarily intended for general audiences. You may have to google, and classes found here may be available on specific Windows operating systems and/or license types only.

To get a list of WMI namespaces available on your computer, run the code below:

# 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 code may run for some time, so grab a coffee. The result is the list of namespaces available on your machine and may look similar to this:

 
root
rootsubscription
rootDEFAULT
rootCIMV2
rootmsdtc
rootCli
rootIntel_ME
rootSECURITY
rootHyperVCluster
rootSecurityCenter2
rootRSOP
rootPEH
rootStandardCimv2
rootWMI
rootMSPS
rootdirectory
rootPolicy
rootvirtualization
rootInterop
rootHardware
rootServiceModel
rootSecurityCenter
rootMicrosoft
rootAppv
rootdcim
rootCIMV2mdm
rootCIMV2Security
rootCIMV2power
rootCIMV2TerminalServices
rootHyperVClusterv2
rootRSOPUser
rootRSOPComputer
rootStandardCimv2embedded
rootdirectoryLDAP
rootvirtualizationv2
rootMicrosoftHomeNet
rootMicrosoftprotectionManagement
rootMicrosoftWindows
rootMicrosoftSecurityClient
rootMicrosoftUev
rootdcimsysman
rootCIMV2mdmdmmap
rootCIMV2SecurityMicrosoftTpm
rootCIMV2SecurityMicrosoftVolumeEncryption
rootMicrosoftWindowsRemoteAccess
rootMicrosoftWindowsDns
rootMicrosoftWindowsPowershellv3
rootMicrosoftWindowsHgs
rootMicrosoftWindowsWindowsUpdate
rootMicrosoftWindowsDeviceGuard
rootMicrosoftWindowsTaskScheduler
rootMicrosoftWindowsDesiredStateConfigurationProxy
rootMicrosoftWindowsSmbWitness
rootMicrosoftWindowsWdac
rootMicrosoftWindowsStorageReplica
rootMicrosoftWindowswinrm
rootMicrosoftWindowsAppBackgroundTask
rootMicrosoftWindowsDHCP
rootMicrosoftWindowsPS_MMAgent
rootMicrosoftWindowsStorage
rootMicrosoftWindowsHardwareManagement
rootMicrosoftWindowsSMB
rootMicrosoftWindowsEventTracingManagement
rootMicrosoftWindowsDesiredStateConfiguration
rootMicrosoftWindowsAttestation
rootMicrosoftWindowsCI
rootMicrosoftWindowsdfsn
rootMicrosoftWindowsDeliveryOptimization
rootMicrosoftWindowsDefender
rootdcimsysmanbiosattributes
rootdcimsysmanwmisecurity
rootMicrosoftWindowsRemoteAccessClient
rootMicrosoftWindowsStoragePT
rootMicrosoftWindowsStorageProviders_v2
rootMicrosoftWindowsStoragePTAlt  
 

Once you know the names of namespaces, use the previous parts of this mini-series to query the WMI class names located in a given namespace. For example, the code below lists all WMI classes in the namespace ‘rootMicrosoftWindowsWindowsUpdate’:

$ns = 'rootMicrosoftWindowsWindowsUpdate'
Get-CimClass -Namespace $ns | 
  Select-Object -ExpandProperty CimClassName | 
  Sort-Object

Class names that start with a double underscore are for internal purposes:

 
__AbsoluteTimerInstruction
__ACE
__AggregateEvent
__ClassCreationEvent
__ClassDeletionEvent
__ClassModificationEvent
__ClassOperationEvent
__ClassProviderRegistration
__ConsumerFailureEvent
__Event
__EventConsumer
__EventConsumerProviderRegistration
__EventDroppedEvent
__EventFilter
__EventGenerator
__EventProviderRegistration
__EventQueueOverflowEvent
__ExtendedStatus
__ExtrinsicEvent
__FilterToConsumerBinding
__IndicationRelated
__InstanceCreationEvent
__InstanceDeletionEvent
__InstanceModificationEvent
__InstanceOperationEvent
__InstanceProviderRegistration
__IntervalTimerInstruction
__MethodInvocationEvent
__MethodProviderRegistration
__NAMESPACE
__NamespaceCreationEvent
__NamespaceDeletionEvent
__NamespaceModificationEvent
__NamespaceOperationEvent
__NotifyStatus
__NTLMUser9X
__ObjectProviderRegistration
__PARAMETERS
__PropertyProviderRegistration
__Provider
__ProviderRegistration
__QOSFailureEvent
__SecurityDescriptor
__SecurityRelatedClass
__SystemClass
__SystemEvent
__SystemSecurity
__thisNAMESPACE
__TimerEvent
__TimerInstruction
__TimerNextFiring
__Trustee
__Win32Provider
CIM_ClassCreation
CIM_ClassDeletion
CIM_ClassIndication
CIM_ClassModification
CIM_Error
CIM_Indication
CIM_InstCreation
CIM_InstDeletion
CIM_InstIndication
CIM_InstModification
MSFT_ExtendedStatus
MSFT_WmiError
MSFT_WUOperations
MSFT_WUSettings
MSFT_WUUpdate  
 

To query the class MSFT_WUSettings in this namespace (if present on your machine), run this:

$ns = 'rootMicrosoftWindowsWindowsUpdate'
Get-CimInstance -ClassName MSFT_WUSettings -Namespace $ns

The result is an exception which indicates that you may be up for surprises when exploring new and sparsely documented internal WMI classes. Depending on your operating system and license type, operations may or may not be supported. If they are not supported, you may end up with a “provider failure” exception.

In addition, some WMI classes (like the ones in this namespace) are not so much designed to contain properties and return information. Instead, they contain methods (commands), in this case to manage Windows Update:

$ns = 'rootMicrosoftWindowsWindowsUpdate'
Get-CimClass -Namespace $ns -ClassName 'MSFT_WUOperations' |
  Select-Object -ExpandProperty CimClassMethods

The result shows the methods:

 
Name           ReturnType Parameters                              Qualifiers           
----           ---------- ----------                              ----------           
ScanForUpdates     UInt32 {SearchCriteria, Updates}               {implemented, static}
InstallUpdates     UInt32 {DownloadOnly, Updates, RebootRequired} {implemented, static}
 

Here is a practical example for Windows Server 2019 machines. The script remotely accesses the servers (in parallel) and uses local WMI to check for security updates, then installs them:

# list of names of Windows Server 2019 machines to update:
$servers="Server2019-IIS","Server2019-AD"

$ns = "root/Microsoft/Windows/WindowsUpdate"
$class = "MSFT_WUOperations"

Invoke-Command -ComputerName $servers -ScriptBlock {
    # find missing updates:
    $arg = @{SearchCriteria="IsInstalled=0 AND AutoSelectOnWebSites=1"}
    $r = Invoke-CimMethod -Namespace $ns -ClassName $class -MethodName ScanForUpdates -Arguments $arg

    # install missing updates:
    if ($r.Updates)
    {
        $arg = @{Updates=$r.Updates}
        Invoke-CimMethod -Namespace $ns -ClassName $class -MethodName InstallUpdates -Arguments $arg
    }
}

Note that the code above works on Windows Server 2019 but fails on Windows Server 2016 (because WMI class names slightly changed). If you still would like to dig deeper, we can highly recommend https://github.com/microsoft/MSLab/blob/master/Scenarios/Windows%20Update/readme.md which is a rich set of examples on how to use WMI to manage Windows Updates on Windows Servers.

And if you’re interested in WMI in general, head over to https://powershell.one/wmi/commands for more information.


Twitter This Tip! ReTweet this Tip!