Tuesday, December 30, 2008

PowerShell’s [WMICLASS] Type accelerator

In January of this year, I wrote a basic article on PowerShell’s WMI Type Accelerators. A type accelerator is, in effect,a shortcut to some underlying .NET component. PowerShell comes with three type accellerators for WMI:
  • [WMI] – a shortcut way of getting to a single instance of a class. I described this type accellerator in an article in February.
  • [WMICLASS] – a short cut to a WMI Class definition to enable access to the class’s static properties and methods. I describe this type accelerator below.
  • [WMISEARCHER] – a short cut to .NET’s ManagementObjectSearcher enabling you to search for objects easily. This type accellerator is an opportunity for a future article.
The [WMICLASS] type accelerator takes a string containing a relative or absolute path to an WMI class, and returns a a System.Management.ManagementClass object that represents the specified class (as opposed to an occurance of that class). For example let’s take a look at the Win32_Share WMI Class. First, look at what Get-WMIObject returns, then look at what the [WMICLASS] type accelerator returns:
 PS c:\foo:\> Get-WMIOBjecct Win32_share | get-memberm
  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.String Descr...
AccessMask          Property     System.UInt32 AccessMask {get;set;}
AllowMaximum        Property     System.Boolean AllowMaximum {get;set;}
Caption             Property     System.String Caption {get;set;}
Description         Property     System.String Description {get;set;}
InstallDate         Property     System.String InstallDate {get;set;}
MaximumAllowed      Property     System.UInt32 MaximumAllowed {get;set;}
Name                Property     System.String Name {get;set;}
Path                Property     System.String Path {get;set;}
Status              Property     System.String Status {get;set;}
Type                Property     System.UInt32 Type {get;set;}
__CLASS             Property     System.String __CLASS {get;set;}
__DERIVATION        Property     System.String[] __DERIVATION {get;set;}
__DYNASTY           Property     System.String __DYNASTY {get;set;}
__GENUS             Property     System.Int32 __GENUS {get;set;}
__NAMESPACE         Property     System.String __NAMESPACE {get;set;}
__PATH              Property     System.String __PATH {get;set;}
__PROPERTY_COUNT    Property     System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH           Property     System.String __RELPATH {get;set;}
__SERVER            Property     System.String __SERVER {get;set;}
__SUPERCLASS        Property     System.String __SUPERCLASS {get;set;}
PSStatus            PropertySet  PSStatus {Status, Type, Name}
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime   ScriptMethod System.Object ConvertToDateTime();

PS c:\foo:\> [WMICLASS]'Win32_share' | get-member
   TypeName: System.Management.ManagementClass#ROOT\cimv2\Win32_Share
Name                MemberType    Definition
----                ----------    ----------
Name                AliasProperty Name = __Class
Create              Method        System.Management.ManagementBaseObject Create(System.String Path, System.String Name, System.UInt32 ...
__CLASS             Property      System.String __CLASS {get;set;}
__DERIVATION        Property      System.String[] __DERIVATION {get;set;}
__DYNASTY           Property      System.String __DYNASTY {get;set;}
__GENUS             Property      System.Int32 __GENUS {get;set;}
__NAMESPACE         Property      System.String __NAMESPACE {get;set;}
__PATH              Property      System.String __PATH {get;set;}
__PROPERTY_COUNT    Property      System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH           Property      System.String __RELPATH {get;set;}
__SERVER            Property      System.String __SERVER {get;set;}
__SUPERCLASS        Property      System.String __SUPERCLASS {get;set;}
ConvertFromDateTime ScriptMethod  System.Object ConvertFromDateTime();
ConvertToDateTime   ScriptMethod  System.Object ConvertToDateTime();
In this example, you can see that Get-WMIObject returns System.Management.ManagementObject objects, while [WMICLASS} returns System.Management.ManagementClass objects – in other words, different object types with different members. I note that the MSDN library documentation does not really differentiate static and object members clearly – so you just have to know which is which when dealing with WMI classes.
The object occurrences returned from Get-WMIObject contain three methods: Delete, GetAccessMask and SetShareInfo. These three methods operate on a particular occurrence, i.e. Delete means “delete this occurrence”. However, the object returned from [WMICLASS} both contains none of those three dynamic methods, but does create a static method: Create, i.e. create a new share.
Why bother with [WMICLASS] you might ask. The answer is simple: to access the static methods and properties/fields that the class exposes. In the case of theWin32_Share class, the class has a static method (create) and three dynamic methods( delete, GetAccessMask and SetShareInfo). If you want to create a new share, then use [WMICLASS] to get access to the create method. You can get access to the Delete method by getting the appropriate method. This bit of code illustrates this:

    Demonstrates WMI and Win32_Share
    This script looks at objects retured from Get-WMIObject, and [WMICLASS] and demonstrates
    the use of a static method (create) and a dynamic or object method (delete).
    Author   : Thomas Lee - tfl@psp.co.uk
    Left as an exercise for the reader

# Display shares at start
$start = get-wmiobject win32_share | where {$_.name -match "Foo"}
if ($start) {
  "{0} foo shares at start, as follows:" -f $start.count;
else {"No foo shares"}

# Create a foo22 share
"";"Adding Foo22 share"
$class = [WMICLASS]'win32_share'
$ret = $class.create("c:\foo", "foo22", 0,$null,"Test Share Creation with WMI")
if ($ret.returnvalue -eq 0){
"Foo22 Share created OK"}
else {
"Share not created, error code: {0}" -f $ret.returnvalue

# Display results
"";"Foo shares now:"
get-wmiobject win32_share | where {$_.name -match "foo"}

# Delete the foo22 share
$del = Get-WmiObject win32_share | where {$_.name -eq "foo22"}
$ret = $del.delete()
if ($ret.returnvalue -eq 0){
"share deleted OK"}
else {
"Share not deleted, error code: {0}" -f $ret.returnvalue

# Display final results
"";"Foo at the end:"
$finish = get-wmiobject win32_share | where {$_.name -match "foo"}
if ($finish) {
  "{0} foo shares at the end, as folllows:" -f $start.count;
else {"No foo shares at the end:"}
This sample, after the now obligatory Advanced Function help stuff, obtains and displays any shares on the local system that contain the string “foo”. Then, in line 24 the scripts gets the Win32_Share class, and in line 25 used the create static method to create a new share (Foo22). In line 39, the script deletes the newly added share, and finally prints out the remaining shares matching “foo”.
In summary, the [WMICLASS] gives you access to the static methods or members exposed by a WMI class.


hung said...

You are right but you complicate the issue.
I recently work with many ways (powershell 2, powershell 1 to work with wmi object).
In fact, there is a trick to translate vbs code with WMI to powershell 1.

Remember the createinstance() and you are ok.

$a = [WMICLASS]'Win32_share'
$a | get-member

#That is what you have
#Here is what you need to learn

$b = $a.CreateInstance()
$b | get-member

That is how you get an object from a class

hung said...

did you get my comment?

Thomas said...

Hung, I think you may have misunderstood my post. WMI classes can have static methods, not available from an instance. The Win32_Share class, as illustrated on this article is one example. You do NOT need to create an instance in order to access the class's static methods. You can use the [WMICLASS] type accelerator to get to the static method. HTH

Josh Einstein said...

Dude. This web page just started playing a radio commercial for a car dealership. What the hell? (Google Chrome showed the audio icon in the tab for this page. As soon as I switched focus back to it, it stopped.)