Improved Support for WMI

<Edited 7/2/2006 to add tags and categories>
We have recently completed work on improved support for WMI including:



  1. Improved Adapters for WMI objects and classes

    1. Most notably the ability to easily invoke methods on both

  2. Direct language support for WMI

    1. Type accelerators for [WMI], [WMICLASS], and [WMISEARCHER]

Everyone that uses WMI owes a debt of gratitude to Greg Ramsey.  Greg did an MMS session and lab focused on Scripting SMS using VBscript and Windows PowerShell.  Jim Truher and I joined Greg to host a Birds of a Feather (BOF) session on Scripting.  Greg was quite enthusiastic about the power of Windows PowerShell but during the BOF someone asked him directly, “So which is it – should we be using VBscript or Windows PowerShell to script SMS”.  I forgot exactly what Greg said but it was along the line so of, “if you want to do reporting, use Windows PowerShell because it is very powerful but if you want to get things done, use VBScript because you can’t invoke WMI methods (at least not easily)”.


This was a real wake up call for us.  Greg is exactly the sort of person that we want to be a ardent, unabashed, no reservations, hard core Windows PowerShell user and the message was loud and clear – almost but not quite


We knew that our WMI support was not what we wanted it to be but as I’ve mentioned many times, to ship is to choose.  We thought that we had reasonable support and that WMI users wouldn’t be phased by some of the deficiencies – yes calling methods was complex but we figured that if you were using WMI, you were self-qualified as being able to cope with complexity :-)


Just to be precise, you could always call WMI methods but you had to do so using the Invoke_Method() call pass it the name of the Method and then all the parameters encoded as an array.   It was probably total folly to think that this was an acceptable user-experience but it took Greg’s comment to get things moving on the right track.


In RC2 this is what a WMI object looks like:



PS> $g=Get-WmiObject Win32_process -filter ‘Name = “calc.exe”‘
PS> $g |gm -membertype “Method,Property”

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


Name                       MemberType Definition
—-                       ———- ———-
AttachDebugger             Method     System.Management.ManagementBaseOb…
GetOwner                   Method     System.Management.ManagementBaseOb…
GetOwnerSid                Method     System.Management.ManagementBaseOb…
SetPriority                Method     System.Management.ManagementBaseOb…
Terminate                  Method     System.Management.ManagementBaseOb…
__CLASS                    Property   System.String __CLASS {get;}
__DERIVATION               Property   System.String[] __DERIVATION {get;}
__DYNASTY                  Property   System.String __DYNASTY {get;}
__GENUS                    Property   System.Int32 __GENUS {get;}
__NAMESPACE                Property   System.String __NAMESPACE {get;}
__PATH                     Property   System.String __PATH {get;}
__PROPERTY_COUNT           Property   System.Int32 __PROPERTY_COUNT {get;}
__RELPATH                  Property   System.String __RELPATH {get;}
……….


Notice that the Methods are now the WMI methods for that particular WMIObject (and not the Methods for WMI).  If you want those, you can still get them using PSBASE (Remember – PSBASE is the way to bybass our type Adapter and get an the native capabilities of an object).



PS> $g.psbase |gm -membertype Method

   TypeName: System.Management.Automation.PSMemberSet


Name                      MemberType Definition
—-                      ———- ———-
add_Disposed              Method     System.Void add_Disposed(EventHandl…
Clone                     Method     System.Object Clone()
CompareTo                 Method     System.Boolean CompareTo(Management…
CopyTo                    Method     System.Management.ManagementPath Co…
CreateObjRef              Method     System.Runtime.Remoting.ObjRef Crea…
Delete                    Method     System.Void Delete(), System.Void D…
Dispose                   Method     System.Void Dispose()
Equals                    Method     System.Boolean Equals(Object obj)
Get                       Method     System.Void Get(), System.Void Get(…
get_ClassPath             Method     System.Management.ManagementPath ge…
get_Container             Method     System.ComponentModel.IContainer ge…
get_Item                  Method     System.Object get_Item(String prope…
get_Options               Method     System.Management.ObjectGetOptions …
get_Path                  Method     System.Management.ManagementPath ge…
get_Properties            Method     System.Management.PropertyDataColle…
get_Qualifiers            Method     System.Management.QualifierDataColl…
get_Scope                 Method     System.Management.ManagementScope g…
get_Site                  Method     System.ComponentModel.ISite get_Site()
get_SystemProperties      Method     System.Management.PropertyDataColle…
GetHashCode               Method     System.Int32 GetHashCode()
GetLifetimeService        Method     System.Object GetLifetimeService()
GetMethodParameters       Method     System.Management.ManagementBaseObj…
GetPropertyQualifierValue Method     System.Object GetPropertyQualifierV…
GetPropertyValue          Method     System.Object GetPropertyValue(Stri…
GetQualifierValue         Method     System.Object GetQualifierValue(Str…
GetRelated                Method     System.Management.ManagementObjectC…
GetRelationships          Method     System.Management.ManagementObjectC…
GetText                   Method     System.String GetText(TextFormat fo…
GetType                   Method     System.Type GetType()
InitializeLifetimeService Method     System.Object InitializeLifetimeSer…
InvokeMethod              Method     System.Object InvokeMethod(String m…
Put                       Method     System.Management.ManagementPath Pu…
remove_Disposed           Method     System.Void remove_Disposed(EventHa…
set_Item                  Method     System.Void set_Item(String propert…
set_Options               Method     System.Void set_Options(ObjectGetOp…
set_Path                  Method     System.Void set_Path(ManagementPath…
set_Scope                 Method     System.Void set_Scope(ManagementSco…
set_Site                  Method     System.Void set_Site(ISite value)
SetPropertyQualifierValue Method     System.Void SetPropertyQualifierVal…
SetPropertyValue          Method     System.Void SetPropertyValue(String…
SetQualifierValue         Method     System.Void SetQualifierValue(Strin…
ToString                  Method     System.String ToString()


But now that the Instance properties are exposed, WMI objects act more like “normal” objects:

PS> $g.GetOwner()
__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT : 3
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
Domain           : NTDEV
ReturnValue      : 0
User             : jsnover


PS> $g.Terminate()
__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT : 1
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
ReturnValue      : 0


 


We have also changed the Adapted view of WMI Classes.  These used to share the same adapter as WMI Instances which meant that you saw instance properties, which makes no sense.  Here is what a WMI Class now looks like:

PS>
$c  = Get-WmiObject -list |where {$_.Name -eq “Win32_Process”}
PS> $c |Format-List *

Name             : Win32_Process
__GENUS          : 1
__CLASS          : Win32_Process
__SUPERCLASS     : CIM_Process
__DYNASTY        : CIM_ManagedSystemElement
__RELPATH        : Win32_Process
__PROPERTY_COUNT : 45
__DERIVATION     : {CIM_Process, CIM_LogicalElement, CIM_ManagedSystemEleme
                   nt}
__SERVER         : JPSLAP04
__NAMESPACE      : ROOT\cimv2
__PATH           :
\\JPSLAP04\ROOT\cimv2:Win32_Process


PS> $c | Get-Member -MemberType Method
   TypeName: System.Management.ManagementClass#ROOT\cimv2\Win32_Process


Name   MemberType Definition
—-   ———- ———-
Create Method     System.Management.ManagementBaseObject Create(System.S…


And you can use it just as you would expect

PS> $c.Create(“Calc.exe”)
__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT : 2
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
ProcessId        : 2948
ReturnValue      : 0


 


 


In addition to these, we decided to add direct language support for WMI into Windows PowerShell. 


[WMISEARCHER] is a type accelerator for a ManagementObjectSearcher. It can take a string constructor to create a searcher that you can then do a GET() on:


PS> $s = [WmiSearcher]’Select * from Win32_Process where Handlecount > 1000′


PS> $s.Get() |sort handlecount |ft handlecount,__path,name -auto


handlecount __PATH                                            name
———– ——                                            —-
       1105
\\JPSLAP04\root\cimv2:Win32_Process.Handle=”3724” powershell…
       1132
\\JPSLAP04\root\cimv2:Win32_Process.Handle=”1388” winlogon.exe
       1495
\\JPSLAP04\root\cimv2:Win32_Process.Handle=”2852” iexplore.exe
       1699
\\JPSLAP04\root\cimv2:Win32_Process.Handle=”1204” OUTLOOK.EXE
       1719
\\JPSLAP04\root\cimv2:Win32_Process.Handle=”1912” iexplore.exe
       2579
\\JPSLAP04\root\cimv2:Win32_Process.Handle=”1768” svchost.exe


 


[WMI] is a type accelerator for ManagementObject. This has a string constructor taking a local or absolute WMI Path to a WMI instace and returning a object bound to that instance:


PS> $p = [WMI]’\\JPSLAP04\root\cimv2:Win32_Process.Handle=”1204″‘
PS> $p.Name
OUTLOOK.EXE


 


[WMICLASS] is a type accelerator for ManagementClass. This has a string constructor taking a local or absolute WMI Path to a WMI class and returning a object bound to that class:



PS> $c = [WMICLASS]”root\cimv2:WIn32_Process”
PS> $c |fl *

Name             : Win32_Process
__GENUS          : 1
__CLASS          : Win32_Process
__SUPERCLASS     : CIM_Process
__DYNASTY        : CIM_ManagedSystemElement
__RELPATH        : Win32_Process
__PROPERTY_COUNT : 45
__DERIVATION     : {CIM_Process, CIM_LogicalElement, CIM_ManagedSystemEleme
                   nt}
__SERVER         : JPSLAP04
__NAMESPACE      : ROOT\cimv2
__PATH           :
\\JPSLAP04\ROOT\cimv2:Win32_Process


We think that these changes make Windows PowerShell THE best environment to use and script WMI.  When RC2 comes out towards the end of the summer, you’ll be able to kick the tires on these new features and let us know if you agree. 


I want to highlight the role of user feedback in these changes.  If it wasn’t for Greg speaking up and giving us honest feedback about where we were not doing a good enough job, these changes would not have been made.  So hat’s off to Greg but also – if there is something about Windows PowerShell that you don’t like – let us know – we really are listening.


Enjoy!


Jeffrey Snover
Windows PowerShell Architect


PSMDTAG:FAQ: How do i invoke a method on a WMI class?
PSMDTAG:FAQ: How do i invoke a method on a WMI object?
PSMDTAG:FAQ: How can I use WQL?
PSMDTAG:FAQ: How do I use WMI?
PSMDTAG:FAQ: How do I bind to a WMI Instance from a WMI PATH?
PSMDTAG:TYPE:WMI [WMI] [WMICLASS] [WMISEARCHER]
PSMDTAG:TYPE:WMI  Invoking methods