Introduction to WMI Basics with PowerShell Part 2 (Exploring WMI using WMI and CIM Cmdlets)

In the previous blog post I covered how to explorer WMI using a GUI tool, now lets look at how to explorer WMI first using the WMI Cmdlets that are found in PowerShell v2 and PowerShell v3, then we will look at how to use CIM Cmdlets that where introduced in PowerShell v3 and the improvements Microsoft did to make using WMI even better in PowerShell v3.

Exploring WMI with WMI Cmdlets

Lets first lets look at the WMI Cmdlets that are available to us using the Get-Command cmdlet:
Get-Command -noun wmi* 

PS C:\> Get-Command -Noun wmi*

CommandType Name ModuleName
----------- ---- ----------
Cmdlet Get-WmiObject Microsoft.PowerShell.Management
Cmdlet Invoke-WmiMethod Microsoft.PowerShell.Management
Cmdlet Register-WmiEvent Microsoft.PowerShell.Management
Cmdlet Remove-WmiObject Microsoft.PowerShell.Management
Cmdlet Set-WmiInstance Microsoft.PowerShell.Management

When working with WMI Cmdlets the most used one is the Get-WmiObject. Lets start by exploring and enumerating the different Namespaces. On the GUI this are the ones shown in a folder structure:

image

Lets look at all the Namespaces under Root by looking at the __namespace class:

Get-WmiObject -Class __Namespace -Namespace root | select name 

PS C:\> Get-WmiObject -Class __Namespace -Namespace root | select name

name
----
subscription
DEFAULT
CIMV2
msdtc
Cli
nap
SECURITY
SecurityCenter2
RSOP
StandardCimv2
WMI
directory
Policy
Interop
Hardware
ServiceModel
SecurityCenter
ThinPrint
Microsoft
aspnet

Now that we enumerated the namespaces under root we can look at the other namespaces by just appending them to the original namespace we queried allowing us to navigate the namespaces:

Get-WmiObject -Class __Namespace -Namespace root\CIMV2 | select name 

PS C:\> Get-WmiObject -Class __Namespace -Namespace root\CIMV2 | select name

name
----
Security
power
ms_409
TerminalServices
Applications

Now lets look at enumerating the Classes under the namespace, this is done by using the –list parameter. The list parameter does provide one flexibility most free GUI do not provide and this is filtering the class names using wildcards:

 Get-WmiObject -list *account* 

PS C:\> Get-WmiObject -list *account*


NameSpace: ROOT\cimv2

Name Methods Properties
---- ------- ----------
MSFT_NetBadAccount {} {SECURITY_DESCRIPTOR, TIME_CREATED}
Win32_Account {} {Caption, Description, Domain, InstallDate...
Win32_UserAccount {Rename} {AccountType, Caption, Description, Disabled.
Win32_SystemAccount {} {Caption, Description, Domain, InstallDate...
Win32_AccountSID {} {Element, Setting}

To list all the classes we just use * as the wildcard to have it list all classes, we can choose what name space to enumerate using the –namespace parameter.

Get-WmiObject -list *sensor* -Namespace root\cimv2\power 

PS C:\> Get-WmiObject -list *sensor* -Namespace root\cimv2\power


NameSpace: ROOT\cimv2\power

Name Methods Properties
---- ------- ----------
CIM_Sensor {RequestStateChan... {AdditionalAvailability, Availability, AvailableRequestedStates,...
CIM_NumericSensor {RequestStateChan... {Accuracy, AdditionalAvailability, Availability, AvailableReques...

To get details on a class it is not as simple as a single command:

(gwmi -list win32_service -Amended).qualifiers | Select name, value | ft -AutoSize -Wrap

PS C:\> (gwmi -list win32_service -Amended).qualifiers | Select name, value | ft -AutoSize -Wrap

Name Value
---- -----
Description The Win32_Service class represents a service on a Win32 computer system. A service application conforms to
the interface rules of the Service Control Manager (SCM) and can be started by a user automatically at
system boot through the Services control panel utility, or by an application that uses the service functions
included in the Win32 API. Services can execute even when no user is logged on to the system.
DisplayName Services
dynamic True
Locale 1033
provider CIMWin32
SupportsUpdate True
UUID {8502C4D9-5FBB-11D2-AAC1-006008C78BC7}

To simplify the process of getting information on a class I recommend that you create a function like the following and place it in your user PowerShell profile in %UserProfile%\My Documents\WindowsPowerShell\profile.ps1 :

function Get-WMIClassInfo

{

param(

[string]$className

)

(Get-WmiObject -list $className -Amended).qualifiers | Select-Object name, value

}

This will make the function available to aid in getting information about classes:

 Get-WMIClassInfo win32_process | ft -AutoSize -Wrap 

PS C:\> Get-WMIClassInfo win32_process | ft -AutoSize -Wrap

Name Value
---- -----
CreateBy Create
DeleteBy DeleteInstance
Description The Win32_Process class represents a sequence of events on a Win32 system. Any sequence consisting of the
interaction of one or more processors or interpreters, some executable code, and a set of inputs, is a
descendent (or member) of this class.
Example: A client application running on a Win32 system.
DisplayName Processes
dynamic True
Locale 1033
provider CIMWin32
SupportsCreate True
SupportsDelete True
UUID {8502C4DC-5FBB-11D2-AAC1-006008C78BC7}

In WMI a class can have 2 types of states:


  • Class it self with its own list of Static Methods and Properties.
  • Class Instances  these are the representation of state of several components of the OS or Hardware that are reference under the class.

One good way to illustrate this would be to look at the Win32_Process class, lets look at the class it self for thise we use with the Get-WmiObject cmdlet the –list paramter and the name of the class to get only the class itself and look at the methods we have available:

 Get-WmiObject -list win32_process | Get-Member -MemberType Method 

PS C:\> Get-WmiObject -list win32_process  | Get-Member -MemberType Method


TypeName: System.Management.ManagementClass#ROOT\cimv2\Win32_Process

Name MemberType Definition
---- ---------- ----------
Create Method System.Management.ManagementBaseObject Create(System.String Commandline ...

As we can see we only have one and it is to create a process. We can even use it to create say a notepad.exe process:

$win32proc = Get-WmiObject -list win32_process

$win32proc.Create("notepad.exe")

PS C:\> $win32proc = Get-WmiObject -list win32_process
PS C:\> $win32proc.Create("notepad.exe")


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

A return value of 0 means that it ran successfully and notepad should pop in you taskbar on Windows. When we look at instances we just use the –Class parameter with the Get-WmiObject cmdlet and give it the class we want to get the instances off, when we look at the methods we see we get a different set of methods since we are now working with an instance of each of the running processes on the system:

 Get-WmiObject -Class win32_process | Get-Member -MemberType method 

PS C:\> Get-WmiObject -Class win32_process | Get-Member -MemberType method


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

Name MemberType Definition
---- ---------- ----------
AttachDebugger Method System.Management.ManagementBaseObject AttachDebugger()
GetOwner Method System.Management.ManagementBaseObject GetOwner()
GetOwnerSid Method System.Management.ManagementBaseObject GetOwnerSid()
SetPriority Method System.Management.ManagementBaseObject SetPriority(System.Int32 Priority)
Terminate Method System.Management.ManagementBaseObject Terminate(System.UInt32 Reason)

 

Exploring WMI with CIM cmdlets

We can see on the latest versions of Windows (Windows 8 and Windows 2012) that Microsoft is advancing its implementation of an open standard for management with Common Information Model (CIM) by integrating it with Windows Remote Management v3 that are part of the Windows Management Framework 3. We can see this in the new Server Manager tool where it uses WinRM for management on Windows 2012. WinRM being based on Microsoft implementation of WS-Management Protocol, a standard Simple Object Access Protocol (SOAP)-based, firewall-friendly protocol that allows hardware and operating systems, from different vendors, to interoperate. This is a shift to provide more interoperability with other platforms and products and Microsoft provides a new set of cmdlets for this.

We can use the Get-Command cmdlet to list the CIM cmdlets that are available in PowerShell v3:

 Get-Command -module CimCmdlets 

PS C:\> Get-Command -module CimCmdlets

CommandType Name ModuleName
----------- ---- ----------
Cmdlet Get-CimAssociatedInstance CimCmdlets
Cmdlet Get-CimClass CimCmdlets
Cmdlet Get-CimInstance CimCmdlets
Cmdlet Get-CimSession CimCmdlets
Cmdlet Invoke-CimMethod CimCmdlets
Cmdlet New-CimInstance CimCmdlets
Cmdlet New-CimSession CimCmdlets
Cmdlet New-CimSessionOption CimCmdlets
Cmdlet Register-CimIndicationEvent CimCmdlets
Cmdlet Remove-CimInstance CimCmdlets
Cmdlet Remove-CimSession CimCmdlets
Cmdlet Set-CimInstance CimCmdlets

Another advantage in addition to using WinRM and also being able to connect to other platforms like Linux or Network equipment that conforms to the CIM standard Microsoft added tab completion for class names and properties in the CIM cmdlets allowing for simpler discovery of classes.  To list namespaces we would use the Get-CimInstance cmdlet, we can use the tab completion by doing Get-CimInstance __name<tab> and have it auto complete it:

Get-CimInstance __namespace 

PS C:\> Get-CimInstance __namespace

Name PSComputerName
---- --------------
Security
power
ms_409
TerminalServices
Applications

If we do not specify a namespace with the –namespace parameter it will enumerate the default one of Root\CIMv2.

For enumerating classes we use the Get-CimClass cmdlet:

 Get-CimClass -ClassName *account* 

PS C:\> Get-CimClass -ClassName *account*


NameSpace: ROOT/CIMV2

CimClassName CimClassMethods CimClassProperties
------------ --------------- ------------------
MSFT_NetBadAccount {} {SECURITY_DESCRIPTOR, TIME_CREATED}
Win32_Account {} {Caption, Description, InstallDate, Name...}
Win32_UserAccount {Rename} {Caption, Description, InstallDate, Name...}
Win32_SystemAccount {} {Caption, Description, InstallDate, Name...}
Win32_AccountSID {} {Element, Setting}

As we can see Microsoft even made it simpler for us by showing the Class Methods and Class properties. But in addition to allowing us to search by class name we can also search by property name and method name giving us more flexibility because there is so much less to type:

 Get-CimClass -MethodName create 

PS C:\> Get-CimClass -MethodName create


NameSpace: ROOT/cimv2

CimClassName CimClassMethods CimClassProperties
------------ --------------- ------------------
Win32_Process {Create, Terminat... {Caption, Description, InstallDate, Name...}
Win32_ScheduledJob {Create, Delete} {Caption, Description, InstallDate, Name...}
Win32_DfsNode {Create} {Caption, Description, InstallDate, Name...}
Win32_BaseService {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_SystemDriver {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_Service {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_TerminalService {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_Share {Create, SetShare... {Caption, Description, InstallDate, Name...}
Win32_ClusterShare {Create, SetShare... {Caption, Description, InstallDate, Name...}
Win32_ShadowCopy {Create, Revert} {Caption, Description, InstallDate, Name...}
Win32_ShadowStorage {Create} {AllocatedSpace, DiffVolume, MaxSpace, UsedSpace...}

For getting the instances of a class we use the Get-CimInstance, as you can see in the WMI cmdlets the Get-WmiObject is the Swiss Army knife that allows you to do most of the  tasks related to WMI while on CIM the tasks have been split in to cmdlets. Lets use the cmdlet to get all the instances for Win32_DiskDrive that represent each of the disk on the system:

PS C:\> Get-CimInstance -ClassName Win32_DiskDrive | fl


Partitions : 2
DeviceID : \\.\PHYSICALDRIVE0
Model : VMware, VMware Virtual S SCSI Disk Device
Size : 64420392960
Caption : VMware, VMware Virtual S SCSI Disk Device

Now when it comes to the use of methods with CIM cmdlets the flexibility we had with WMI cmdlets is sadly missing, with WMI cmdlets when we got the class or the instances of the class as part of the object that was returned we also had methods to each that allowed us to invoke the method and have actions taken against what the class instace represented, with CIM objects we need to use the Invoke-CimMethod cmdlet. Lets look at the same example we used above where we created a notepad.exe process:

Invoke-CimMethod Win32_Process -MethodName create -Arguments @{CommandLine='notepad.exe'} 
x

PS C:\> Invoke-CimMethod Win32_Process -MethodName create -Arguments @{CommandLine='notepad.exe'}

ProcessId ReturnValue PSComputerName
--------- ----------- --------------
2684 0

As it can be seen when a method is invoked with the CIM cmdlet we must provide it the name of the method and if this method takes a parameter we must specify the parameter in a Hash where the key is the parameter name. In WMI cmdlets we would use the invoke-wmimethod, they are similar in operation and getting used to CIM cmdlets just takes a little practice if you have been using WMI cmdlets on PowerShell v2 for a while. Lets look terminating all notepad.exe processes with WMI cmdlet and then with CIM cmdlets so you can see the similarities:

# WMI Cmdlet example

Invoke-WmiMethod -Class win32_Process -Name create -ArgumentList notepad.exe

Get-WmiObject win32_process -Filter "name='notepad.exe'" | foreach {$_.terminate()}

 

# CIM Cmdlet example

Invoke-CimMethod Win32_Process -MethodName create -Arguments @{CommandLine='notepad.exe'}

Get-CimInstance Win32_Process -Filter "name='notepad.exe'" | Invoke-CimMethod -MethodName terminate

PS C:\> Invoke-WmiMethod -Class win32_Process -Name create -ArgumentList notepad.exe


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

PS C:\> Get-WmiObject win32_process -Filter "name='notepad.exe'" | foreach {$_.terminate()}


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

PS C:\> Invoke-CimMethod Win32_Process -MethodName create -Arguments @{CommandLine='notepad.exe'}

ProcessId ReturnValue PSComputerName
--------- ----------- --------------
3316 0


PS C:\> Get-CimInstance Win32_Process -Filter "name='notepad.exe'" | Invoke-CimMethod -MethodName terminate

ReturnValue PSComputerName
----------- --------------
0

As you can see the cmdlets operate very similarly.

I invite you to use the Get-Help cmdlet against each of the cmdlets mentioned here to learn more about them. As always I hope you found the blogpost useful.