Weekend Scripter: Clean Up Your WMI Data Output in PowerShell

Summary: Microsoft Scripting Guy, Ed Wilson, shows you how to use Windows PowerShell to clean up your WMI data output.

Microsoft Scripting Guy, Ed Wilson, is here. So far the Scripting Wife has been scarce. She got up before sunrise (I believe) and headed out to points unknown. Actually, I believe she had scheduled a “chicks breakfast” with her friends who are hanging out down here in Myrtle Beach, South Carolina (and no, it was not a PowerShell Chicks User Group breakfast). But that is OK, because it means that I get to fend for myself. And with a beach, ocean, and tons of cool things to do within walking distance, fending for one’s self was never easier. There is even wifi on the beach—the only trick is to avoid getting sand in one’s laptop.

The problem with extra “stuff” in a WMI query

The problem of getting “extra stuff” back when you do a WMI data query has been around since Windows PowerShell 1.0 (even longer if you count the beta period). But to be honest, it is not that you get extra stuff back when you perform a WMI query, it is that certain WMI classes have a default output that is configured via the types.ps1xml file. For example, the image that follows illustrates the portion that shows the format XML information for the Win32_BIOS WMI class.

When you perform a basic WMI query, the default display formats the output. This is because the basic query (no specifically requested properties) matches the System.Management.ManagementObject#root\cimv2\Win32_BIOS type that is specified in the format XML file. This information is shown here:

PS C:\> gwmi win32_bios | gm | select typename -Unique

TypeName

--------

System.Management.ManagementObject#root\cimv2\Win32_BIOS

When I use the Property parameter or I perform a custom WQL query, the returned type changes; and therefore, it does not match the type that is defined in the types.ps1xml file, as shown here.

Filtering out the system properties

So what is the “extra stuff” that comes back when a custom WMI query runs? They are system properties. One of the nice things about WMI is that all of the system properties begin with a double underscore ( __ ). In addition, all system WMI classes begin with a double underscore. When you run a WMI query that selects only the name property, a whole bunch of system properties also return. This is shown here:

PS C:\> gwmi -q "select name from win32_bios"

__GENUS : 2

__CLASS : Win32_BIOS

__SUPERCLASS :

__DYNASTY :

__RELPATH :

__PROPERTY_COUNT : 1

__DERIVATION : {}

__SERVER :

__NAMESPACE :

__PATH :

Name : Default System BIOS

One way to clean up the output is to filter these properties by using a range in either Format-Table or Format-List as shown here:

PS C:\> gwmi -q "select name from win32_bios" | fl [a-zA-Z]*

Name : Default System BIOS

Scope : System.Management.ManagementScope

Path :

Options : System.Management.ObjectGetOptions

ClassPath : Win32_BIOS

Properties : {Name}

SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}

Qualifiers : {dynamic, Locale, provider, UUID}

Site :

Container :

PS C:\> gwmi -q "select name from win32_bios" | ft [a-zA-Z]*

Name Scope Path Options ClassPat Propert SystemP Qualifi Site Contain

h ies roperti ers er

es

---- ----- ---- ------- -------- ------- ------- ------- ---- -------

Defau... Syste... Syste... Win32... {Name} {__G... {dyn...

Unfortunately, in Windows PowerShell 2.0, that filter trick quit working because no sooner do you get rid of one group of system properties, than another group of system properties appears. It does not matter, whether you use the Format-Table cmdlet or if you use the Format-List cmdlet—the extra system properties appear to be here to stay.

Using Format-Table or Format-List

If you specifically choose the properties in your WMI query, you also need to specifically choose them in the Format-Table or Format-List query. This technique is shown here:

PS C:\> gwmi -Property name -Class win32_bios | ft name

name

----

Default System BIOS

PS C:\> gwmi -Property name -Class win32_bios | fl name

name : Default System BIOS

There are at least two things “wrong” with this approach. The first is that once you use a Format-Table, Format-List, or Format-Wide cmdlet, you cannot do anything else with your pipeline because the object is now gone. In other words, the format* cmdlets destroy the pipeline. What is the difference? Well, it can be seen by examining the object in the pipeline.

In the first example, we see that we have a win32_bios management object.

Remove the “extra stuff” and retain the object

The best way to remove the “extra stuff” is to use the Select-Object cmdlet. This cmdlet removes the “stuff” and retains the object-oriented nature of the data. This means that you can do other things with it. In the command that follows, the Name and the ProcessID properties from the Win32_Service WMI class are chosen from the WMI data. Next, the Select-Object cmdlet chooses the same properties. Now they are sent to Get-Member, and the typename is displayed. This is shown here:

Because this is still a management object, we can continue to use Windows PowerShell to massage the data. As shown here, we can use the Sort-Object cmdlet to sort the data, and we can use the –Last parameter to choose the last two services.

One thing that can simplify things is to list the properties that you are interested in obtaining in an array, and then use them directly in your Get-WmiObject and your Select-Object queries. In this way, you only need to type them once. Because I do not like typing quotation marks, I create a single string with the CSV list of property names. Then I use the Splitoperator to create my array. The thing to keep in mind is to not put spaces between the property names. This code is shown here:

$property = "Name,started,StartName" -split ","

gwmi -p $property -cl win32_service | select $property

When you have the properties in an array, you can use them as often as you want without the need to retype them. In the example that follows, the Format-Table cmdlet is used to display a table of service information.

Well, that is about it for right now. The Scripting Wife will be back soon (I imagine), and then she was talking about going to do something. No idea what—just something. But hey, we are at the beach, so there is bound to be something going on. Maybe we can found the Myrtle Beach Windows PowerShell Users Group while we are down here.

This can aslo be commandered into generating a hash and a new object sans system properties.

We can aslo just dump only the non-system properties:

$p=gwmi -list win32_service|select -expand properties|%{$_.Name}

gwmi -cl win32_service | select $p

I believe PosH 3 has the switch you were asking for or, rather, it has a completely redesigned set of CmdLets for WMI which is now formally called CIM. CIM outputs almost identically to the example above using $p.

@K_Schulte yes a switch would be awesome … -nosystemproperties or some such thing. Maybe in PowerShell 4.0

@JRV yes, I will start blogging about PowerShell 3.0 and Windows 8 once it RTM's … I am chomping at the bit, and would LOVE to start blogging about it, but the majority of my readers are not yet playing with the release candidates.

@JRV yes, I will have a LOT of blogging to do in the near future. It is not so much I have been squirrelling away my secrets — I have been putting them in the Microsoft Press Windows PowerShell 3.0 Step by Step book 🙂