New WMI Object

I have one more variation on my recent theme of working with WMI objects. I wanted to come up with something flexible and re-usable where you could specify a WMI class and some properties and get a custom object with all the classes combined. My solution is a function called New-WmiObject.

Function New-WMIObject {            

[cmdletbinding()]            

Param (
      [Parameter(Position=0,ValueFromPipeline=$True,
      HelpMessage="Enter a computername.")]
      [string[]]$computername=$env:computername,
      [Parameter(Position=1,ValueFromPipeline=$False,
      HelpMessage="Enter a hashtable of WMI classes and properties.",
      Mandatory=$True)]
      [hashtable]$hashtable
)            

Begin {
     write-verbose "Starting $($myinvocation.mycommand)"
}#begin            

Process {
 foreach ($computer in $computername) {
 #initialize property hash
     $properties=@{}
     write-verbose "Adding $($computer.toUpper()) to `$properties"
     $properties.Add("Computer",$($computer.toUpper()))
    foreach ($hash in $hashtable) {
        $classes=$hash.keys
        foreach ($class in $classes) {
            write-verbose "Getting $class information on $computer"
            $wmi=Get-WmiObject -Class $class -Property $hash.item($class) `
            -computername $computer
            #create array properties if $wmi returned more than one item
            if ($wmi.count -gt 1) {
                write-verbose "Multiple WMI objects returned"
                #initialize a temporary array
                $array=@()
                foreach ($object in $wmi) {
                    Write-Verbose "Adding $($object.__RELPATH)"
                    $array+=$object | select $hash.item($class)
                }#end foreach $object
                #add the array as a property value
                #strip off win32_ from the class name
                $parsed=$class.Substring($class.indexof("_")+1)
                $properties.Add($parsed,$array)
            }
            else {
                #add each property
                    foreach ($item in $hash.item($class)) {
                    write-verbose "Adding $item = $($wmi.($item))"
                    $properties.Add($item,$($wmi.($item)))
            }
            } #else
        } #foreach $class            

    } #foreach $hash
    Write-Verbose "Creating custom object"
    New-Object PSObject -Property $properties
 } #foreach $computer
} #process            

End {            

 write-verbose "Ending $($myinvocation.mycommand)"
} #end
} #end function

The function takes a computername as either a direct or pipelined value. The default is the local computer. The other value is a hashtable of WMI information. The key is the name of a Win32 WMI class. The value is a comma separated list of properties for that particular class. The function will gather the requested WMI information and write a custom object to the pipeline with each property. This means that you are limited to unique property names in your hashtable. If you have two classes you want to query, each with a property of Version, the function can’t return both values. If someone would like to revise the script to accommodate this that would be great.

The function works best if the WMI classes return single instances. If the WMI class you want to query will return multiple instances, New-WmiObject will work but it will return a property that contains an array of the objects. For example. here’s a hash table I want to use:

$a=@{win32_OperatingSystem="Caption","RegisteredUser","LastBootUpTime";
win32_computersystem="Name","Manufacturer","Model";
win32_bios="Version";
win32_logicaldisk="deviceid","size","freespace","drivetype"}

After loading the function into my shell I can run it like this:

PS C:\> new-wmiobject –hashtable $a

RegisteredUser : Jeff

Version        : TOSQCI – 6040000

Model          : Qosmio X505

LastBootUpTime : 20100514111336.610798-240

Name           : SERENITY

logicaldisk    : {@{deviceid=C:; size=487439986688; freespace=276030799872; dri

                 vetype=3}, @{deviceid=D:; size=; freespace=; drivetype=5}, @{d

                 eviceid=E:; size=1000202039296; freespace=504326586368; drivet

                 ype=3}, @{deviceid=F:; size=; freespace=; drivetype=5}…}

Manufacturer   : TOSHIBA

Caption        : Microsoft Windows 7 Ultimate

Computer       : SERENITY

Notice the Win32_logicaldisk entry from the hashtable is used to define a property name for the collection by stripping off WIn32_. Working with individual properties of the custom object should be pretty straightforward.

PS C:\> $r | format-table Computer,Caption,Model -AutoSize

Computer Caption                       Model                          
——– ——-                       —–                          
GODOT7   Microsoft Windows 7 Ultimate  Latitude D800                  
SERENITY Microsoft Windows 7 Ultimate  Qosmio X505  

If you want to work with the array properties, like logicaldisk in my example, you could try an expression like this:

PS C:\Scripts> $r | select-object -property computer -expand logicaldisk |

where {$_.drivetype -eq 3} | format-table -GroupBy Computer -Property DeviceID,Size,FreeSpace

   Computer: GODOT7

DeviceId                                         Size                 FreeSpace

——–                                         —-                 ———

C:                                       119926681600               45238063104

   Computer: SERENITY

DeviceId                                         Size                 FreeSpace

——–                                         —-                 ———

C:                                       487439986688              276032737280

E:                                      1000202039296              504326586368

J:                                       320070287360               91348078592

I think this function will work just fine as long as you stick to a few classes that return single instances and if you can limit yourself to unique WMI property names. The function has plenty of room for improvement as it is lacking comment based help, support for alternate credentials, and error handling. If you work up a new version I’d be happy to post it.

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

This entry was posted in PowerShell, WMI and tagged , , , , . Bookmark the permalink.

Comments are closed.