Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
August 15, 2025

A Method to the Madness: Exploring WMI Methods

Windows Management Instrumentation (WMI) and Common Information Model (CIM) provide powerful interfaces for managing Windows systems programmatically. While many administrators are familiar with querying WMI classes for information, the ability to invoke methods on these classes opens up a world of system management possibilities. I thought I would take some time to explores the purpose of WMI methods, how to discover them, and the various approaches to invoking them using both traditional WMI cmdlets and modern CIM cmdlets in PowerShell. This is not something you will use every day, but it is handy information to have in your back pocket, especially because working with WMI methods is not as intuitive.

Why WMI Methods?

WMI methods serve as the action-oriented components of the Windows Management Instrumentation framework. While WMI properties provide read-only or read-write access to system information, methods enable you to perform operations, execute functions, and trigger system changes. Think of WMI properties as the "nouns" of system management and WMI methods as the "verbs." We use the "noun" metaphor all the time in PowerShell, including cmdlets built on WMI such as Get-Volume.

The primary purposes of WMI methods include:

System Configuration and Management

WMI methods allow administrators to modify system configurations programmatically. For example, you can change network adapter settings, modify registry values, or update system policies without directly manipulating the underlying components. Ideally, you will be able to find a PowerShell command that abstracts this functionality, but sometimes you need to get down and dirty with WMI methods.

Process and Service Control

Methods provide fine-grained control over processes and services. You can start, stop, pause, or restart services, terminate processes, or create new processes with specific parameters and security contexts.

Commands like Start-Service, Stop-Service, and Stop-Process are built using the .NET Framework to access the Windows APIs for managing services and processes. These are not using WMI methods in the way I am discussing here, but they are similar in that they provide a programmatic interface to manage system components.

Hardware Management

WMI methods enable interaction with hardware components. You can perform operations such as ejecting removable media, resetting network adapters, or configuring BIOS settings on supported systems.

Security Operations

Many WMI classes expose methods for security-related operations, including user account management, permission modifications, and security policy enforcement.

Event Management

WMI methods can trigger events, create event subscriptions, or respond to system events programmatically. I've written about this in the first year of this newsletter. It might be time to revisit that topic.

Remote Management

One of the most powerful aspects of WMI methods is their ability to operate on remote systems, enabling centralized management of distributed environments.

Consider this fundamental example of using a WMI method to restart a service. This code requires Windows PowerShell.

# Using WMI to restart the Windows Time service
$service = Get-WmiObject -Class Win32_Service -Filter "Name='W32Time'"
$result = $service.StopService()
if ($result.ReturnValue -eq 0) {
    Start-Sleep -Seconds 2
    $result = $service.StartService()
    Write-Host "Service restart completed with return value: $($result.ReturnValue)"
}

The WMI service object contains methods like StopService and StartService, which you can invoke to control the service's state.

PS C:\> $service | Get-Member -MemberType method


   TypeName: System.Management.ManagementObject#root\cimv2\Win32_Service

Name                  MemberType Definition
----                  ---------- ----------
Change                Method     System.Management.ManagementBaseObject Chang...
ChangeStartMode       Method     System.Management.ManagementBaseObject Chang...
Delete                Method     System.Management.ManagementBaseObject Delete()
GetSecurityDescriptor Method     System.Management.ManagementBaseObject GetSe...
InterrogateService    Method     System.Management.ManagementBaseObject Inter...
PauseService          Method     System.Management.ManagementBaseObject Pause...
ResumeService         Method     System.Management.ManagementBaseObject Resum...
SetSecurityDescriptor Method     System.Management.ManagementBaseObject SetSe...
StartService          Method     System.Management.ManagementBaseObject Start...
StopService           Method     System.Management.ManagementBaseObject StopS...
UserControlService    Method     System.Management.ManagementBaseObject UserC...

When you invoke a method, you will get a result object.

PS C:\> $result


__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT : 1
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
ReturnValue      : 0
PSComputerName   :

The ReturnValue property indicates the success or failure of the operation, with 0 typically indicating success. For other values, you would need to refer to the WMI documentation for the specific class to understand what the return codes mean.

This simple example demonstrates how WMI methods bridge the gap between information gathering and system modification, providing a programmatic interface for system administration tasks.

Discovery

Before you can effectively use WMI methods, you need to understand how to discover them and their parameters. PowerShell provides several tools for method discovery, with Get-CimClass being the most powerful and modern approach.

Method Discovery with Get-CimClass

The Get-CimClass cmdlet is your primary tool for exploring WMI classes and their associated methods. This cmdlet provides comprehensive information about class structures, including properties, methods, and their parameters.

Basic Class Discovery

To begin exploring WMI methods, start by identifying the classes that contain the functionality you need:

# Find all classes related to processes
PS C:\> Get-CimClass -ClassName "*Process*" | Where CimClassName -notMatch "Perf" | Select-Object CimClassName

CimClassName
------------
Win32_ProcessTrace
Win32_ProcessStartTrace
Win32_ProcessStopTrace
CIM_Process
Win32_Process
CIM_Processor
Win32_Processor
CIM_AssociatedProcessorMemory
Win32_AssociatedProcessorMemory
CIM_ProcessExecutable
Win32_SessionProcess
Win32_ComputerSystemProcessor
Win32_SystemProcesses
CIM_ProcessThread
CIM_OSProcess
Win32_NamedJobObjectProcess
Win32_ProcessStartup

I'm filtering out the performance classes because they are not useful for our purposes. You can also use Get-CimClass to explore other classes related to services, network configurations, and more.

# Find classes related to services
PS C:\> Get-CimClass -ClassName "win32*service*" | Where CimClassName -notMatch "Perf" | Select-Object CimClassName

CimClassName
------------
Win32_BaseService
Win32_Service
Win32_TerminalService
Win32_ApplicationService
Win32_LoadOrderGroupServiceDependencies
Win32_DependentService
Win32_SystemServices
Win32_LoadOrderGroupServiceMembers
Win32_ServiceControl
Win32_ServiceSpecification
Win32_ServiceSpecificationService

The majority of the classes you will use in the Root\CIMV2 namespace start with Win32_.

If you install the PSScriptTools module, you can use the Find-CimClass function to discover classes beyond the Root\CIMV2 namespace. This function provides a more user-friendly interface for searching and filtering classes.

PS C:\> Find-CimClass *adapter | Where CimClassName -notMatch "perf" |
Select-Object @{Name="Namespace";Expression={$_.CimSystemProperties.Namespace}},CimClassName |
Format-Table -AutoSize

Namespace                 CimClassName
---------                 ------------
Root/CIMV2                CIM_NetworkAdapter
Root/CIMV2                Win32_NetworkAdapter
Root/CIMV2/ms_409         CIM_NetworkAdapter
Root/CIMV2/ms_409         Win32_NetworkAdapter
Root/StandardCimv2        MSFT_NetAdapter
Root/StandardCimv2        MSFT_NetEventNetworkAdapter
Root/StandardCimv2        MSFT_NetEventVmNetworkAdapter
Root/StandardCimv2        MSFT_NetImPlatAdapter
Root/StandardCimv2        MSFT_NetIPInterfaceAdapter
Root/StandardCimv2/MS_409 MSFT_NetAdapter
Root/StandardCimv2/MS_409 MSFT_NetEventNetworkAdapter
Root/StandardCimv2/MS_409 MSFT_NetEventVmNetworkAdapter
Root/StandardCimv2/MS_409 MSFT_NetIPInterfaceAdapter
Root/WMI                  MSNdis_EnumerateAdapter
Root/WMI                  MSNdis_WmiEnumAdapter
Root/WMI/ms_409           MSNdis_EnumerateAdapter

Detailed Method Exploration

Once you've identified a class of interest, you can examine its methods in detail:

# Get detailed information about Win32_Process class methods
$processClass = Get-CimClass -ClassName Win32_Process
$processClass.CimClassMethods | Format-Table Name, ReturnType, @{
    Name = "Parameters"
    Expression = { ($_.Parameters | ForEach-Object { "$($_.Name):$($_.CimType)" }) -join ", " }
}

This command provides a comprehensive view of all methods available in the Win32_Process class, including their return types and parameter signatures.

Name                    ReturnType Parameters
----                    ---------- ----------
Create                      UInt32 CommandLine:String, CurrentDirectory:String, ProcessStartupP...
Terminate                   UInt32 Reason:UInt32
GetOwner                    UInt32 Domain:String, User:String
GetOwnerSid                 UInt32 Sid:String
SetPriority                 UInt32 Priority:SInt32
AttachDebugger              UInt32
GetAvailableVirtualSize     UInt32 AvailableVirtualSize:UInt64

If you have the PSScriptTools module installed, you can use the Get-CimClassMethod function to retrieve method details more easily:

PS C:\> Get-CimClassMethod -ClassName Win32_Service


   Class: Root/Cimv2:Win32_Service

Name                  ResultType Parameters
----                  ---------- ----------
Change                UInt32     {DisplayName, PathName, ServiceType, ErrorControl...}
ChangeStartMode       UInt32     {StartMode}
Create                UInt32     {Name, DisplayName, PathName, ServiceType...}
Delete                UInt32     {}
GetSecurityDescriptor UInt32     {Descriptor}
InterrogateService    UInt32     {}
PauseService          UInt32     {}
ResumeService         UInt32     {}
SetSecurityDescriptor UInt32     {Descriptor}
StartService          UInt32     {}
StopService           UInt32     {}
UserControlService    UInt32     {ControlCode}

I'll cover how to use the parameters in a bit.

Filtering Methods by Functionality

You can filter methods based on specific criteria to find exactly what you need:

# Find all methods that contain "Start" in their name across all classes
PS C:\> Get-CimClass | ForEach-Object {
    $className = $_.CimClassName
    $_.CimClassMethods | Where-Object { $_.Name -like "*Start*" } |
    Select-Object @{Name="Class"; Expression={$className}}, Name, ReturnType
}

Class                    Name            ReturnType
-----                    ----            ----------
CIM_Service              StartService        UInt32
Win32_PnPSignedDriver    StartService        UInt32
Win32_BaseService        StartService        UInt32
Win32_BaseService        ChangeStartMode     UInt32
Win32_Service            StartService        UInt32
Win32_Service            ChangeStartMode     UInt32
Win32_TerminalService    StartService        UInt32
Win32_TerminalService    ChangeStartMode     UInt32
Win32_SystemDriver       StartService        UInt32
Win32_SystemDriver       ChangeStartMode     UInt32
CIM_BootService          StartService        UInt32
CIM_ClusteringService    StartService        UInt32
Win32_ApplicationService StartService        UInt32
Win32_PrinterDriver      StartService        UInt32

Or use my Get-CimClassMethod function:

PS C:\> Get-CimClass -classname WIN32_* | foreach {
    Get-CimClassMethod $_.CimClassName -method "Stop*" -WarningAction SilentlyContinue} |
    Select Classname,Name,Parameters

ClassName                Name        Parameters
---------                ----        ----------
Win32_PnPSignedDriver    StopService {}
Win32_BaseService        StopService {}
Win32_Service            StopService {}
Win32_TerminalService    StopService {}
Win32_SystemDriver       StopService {}
Win32_ApplicationService StopService {}
Win32_PrinterDriver      StopService {}

I need to fix a pipeline bug with this function.

Discovering Parameters

Understanding method parameters is crucial for successful method invocation. Each method parameter has specific characteristics including data type, direction (input/output), and whether it's required or optional.

Examining Parameter Details

# Get detailed parameter information for the Create method of Win32_Process
PS C:\> $processClass = Get-CimClass -ClassName Win32_Process
PS C:\> $createMethod = $processClass.CimClassMethods | Where-Object { $_.Name -eq "Create" }
PS C:\> $createMethod.Parameters | Select Name,CimType,Qualifiers

Name                       CimType Qualifiers
----                       ------- ----------
CommandLine                 String {ID, In, MappingStrings}
CurrentDirectory            String {ID, In, MappingStrings}
ProcessStartupInformation Instance {EmbeddedInstance, ID, In, MappingStrings}
ProcessId                   UInt32 {ID, MappingStrings, Out}

This reveals important information about each parameter, including:

  • Name: The parameter identifier
  • CimType: The data type (String, UInt32, Boolean, etc.) required for the parameter value.
  • Qualifiers: Provide additional metadata about the parameters, such as whether they are input, output, or optional. If you see In=True it is a required parameter.
PS C:\> $CreateMethod.Parameters | Where { $_.Qualifiers['In'].Value} | Select Name,CimType

Name                       CimType
----                       -------
CommandLine                 String
CurrentDirectory            String
ProcessStartupInformation Instance

Understanding Parameter Direction

Parameters can be classified as:

  • Input parameters: Values you provide to the method
  • Output parameters: Values the method returns
  • Input/Output parameters: Values that serve both purposes

Here's a code snippet you could use to build a PowerShell function that analyzes parameter directions.

# Analyze parameter directions for the Create method
$createMethod.Parameters | ForEach-Object {
    $direction = 'Unknown'
    if ($_.Qualifiers['In'] -and $_.Qualifiers['Out']) {
        $direction = 'Input/Output'
    }
    elseif ($_.Qualifiers['In']) {
        $direction = 'Input'
    }
    elseif ($_.Qualifiers['Out']) {
        $direction = 'Output'
    }

    [PSCustomObject]@{
        Name      = $_.Name
        Type      = $_.CimType
        Direction = $direction
        Optional  = [bool]$_.Qualifiers['Optional']
    }
}

I would add the class name, namespace, and method name to the output. But this is a good start to understanding the parameters.

Name                          Type Direction Optional
----                          ---- --------- --------
CommandLine                 String Input        False
CurrentDirectory            String Input        False
ProcessStartupInformation Instance Input        False
ProcessId                   UInt32 Output       False

Summary

I think I've overwhelmed you enough for one day. Take some time to use my code samples, and commands from the PSScriptTools module to explore WMI methods. Find something you think you'd like to try, on a non-production system, of course. I'll get into invoking methods next time.

(c) 2022-2025 JDH Information Technology Solutions, Inc. - all rights reserved
Don't miss what's next. Subscribe to Behind the PowerShell Pipeline:
Start the conversation:
GitHub Bluesky LinkedIn About Jeff
Powered by Buttondown, the easiest way to start and grow your newsletter.