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.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
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.