Thursday, July 03, 2014

PowerShell + WMI - Static & Instance Methods

One has to get their feet wet with WMI when it comes to managing ConfigMgr with PowerShell. How ConfigMgr uses WMI ? Not only ConfigMgr but for other products if you leverage WMI with PowerShell then understanding what are Static & Instance methods is important.

But there are lot of places where People stumble ( I did too ). Below is a question asked in Hyderabad PowerShell User Group (PSHUG) showing one of the common point of confusion.

If you are a ConfigMgr Admin then you already know that in SCCM client we have a lot many Client actions that can be triggered remotely. Below are the available SCCM Client actions (In CM 2012) :

Going back to the question, below code will work,which is triggering "Software Inventory" on a remote $machine:

$Client1 = $([WmiClass]"\\$Machine\ROOT\ccm:SMS_Client")

One can get more info on the class SMS_Client & TriggerSchedule Method.

But why are we not able to see the method when we do the below:

$Client2 = Get-WmiObject -ComputerName $Machine -Namespace root\ccm -Class SMS_Client
$Client2 | Get-Member -MemberType *

Note - There are two variables $Client1 & $Client2 

Before we go further would like to clarify one thing first, one can get the WMI Class Object by using the Get-WMIObject cmdlet itself with -List switch

So If I do the below..take note of the -List switch at the end:

$Client3 = Get-WmiObject -Class SMS_client -Namespace Root\CCM -ComputerName $machine -List

Go ahead and see for yourself that the two objects $Client1 and $Client3 are essentially the same :) 

The answer to why the TriggerSchedule method doesn't appear when we pipe it to Get-Member is really simple, Just compare the Type of both the Objects you have at hand

So from above we deduce that those two are essentially 2 different objects so you won't find the TriggerSchedule Method on the $Client2 ;)

This becomes obvious if we think over it --> [WmiClass] type accelerator gives you the WMI Class Object back not the WMI Instance

Detailed Explanation

To clarify things a bit more the Class ($Client1) is a definition of Objects and Instance (Client2) is the manifestation of the class. 

In our question $Client1 is Class and $Client2 is an Instance of the class.

Now a class can have 2 type of methods : 

  1. Static Methods (only available on the class)
  2. Instance Methods (available on the Instances of the class)

So how do we go on getting this key piece of information, whether it is a Static method or not ?

Once you have the class object ($Client1 ) you can explore it. 

So once we have the WMI Class Object we can do the below to take a look at the methods and the qualifiers:
PS> $Client1 | select -ExpandProperty methods | select name,qualifiers

Name                                                        Qualifiers
----                                                        ----------
ResetPolicy                                                 {implemented, static}
RequestMachinePolicy                                        {implemented, static}
EvaluateMachinePolicy                                       {implemented, static}
TriggerSchedule                                             {implemented, static}
RepairClient                                                {implemented, static}
SetAssignedSite                                             {implemented, static}
GetAssignedSite                                             {implemented, static}
SetGlobalLoggingConfiguration                               {implemented, static}
ResetGlobalLoggingConfiguration                             {implemented, static}
SetClientProvisioningMode                                   {implemented, static}

Notice that all the methods on the class are static.

To sum it all let's take a class having both Static and Instance method e.g Win32_Share

PS> Get-WmiObject -Class WIn32_Share -List| select  -ExpandProperty methods | select name,qualifiers

Name                                                        Qualifiers
----                                                        ----------
Create                                                      {Constructor, Implemented, MappingStrings, Static}
SetShareInfo                                                {Implemented, MappingStrings}
GetAccessMask                                               {Implemented, MappingStrings}
Delete                                                      {Destructor, Implemented, MappingStrings}

So the only method which is static is the Create Method and rest are Static.

Verify this is correct by getting the WMI Instances back and using the Get-Member

PS> Get-WmiObject -Class WIn32_Share  | Get-Member -MemberType method -Force

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

Name          MemberType Definition
----          ---------- ----------
Delete        Method     System.Management.ManagementBaseObject Delete()
GetAccessMask Method     System.Management.ManagementBaseObject GetAccessMask()
SetShareInfo  Method     System.Management.ManagementBaseObject SetShareInfo(System.UInt32 MaximumAllowed, System.St...

Notice that the Create method doesn't show up on the WMI Instance cause it is a static method on the class :)

But it does show up on the WMI Class Object

PS> Get-WmiObject -Class win32_Share -ComputerName $Machine -List | Get-Member -MemberType Method

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

Name   MemberType Definition
----   ---------- ----------
Create Method     System.Management.ManagementBaseObject Create(System.String Path, System.String Name, System.UInt3...

I will be presenting a session on the next PSBUG + BITPro meet on the topic
"PowerShell + ConfigMgr - Getting Started" on 19th July, in this session will shed light on this too. The registrations haven't opened yet. So you can keep an eye on the FB group links.