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.
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:
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 namename
----
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 namename
----
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\cimv2Name 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\powerName 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 -WrapName 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 -WrapName 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:
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_ProcessName 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_ProcessName 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)
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 CimCmdletsCommandType 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 __namespaceName 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/CIMV2CimClassName 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/cimv2CimClassName 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 exampleInvoke-WmiMethod -Class win32_Process -Name create -ArgumentList notepad.exeGet-WmiObject win32_process -Filter "name='notepad.exe'" | foreach {$_.terminate()}# CIM Cmdlet exampleInvoke-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 terminateReturnValue 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.