Weekend Scripter: Clean Up Your WMI Data Output in PowerShell

Weekend Scripter: Clean Up Your WMI Data Output in PowerShell

  • Comments 7
  • Likes

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.

Image of command output

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.

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

 

TypeName

--------

System.Management.ManagementObject#\Win32_BIOS

 

PS C:\> gwmi -q "select name from win32_bios" | gm | select typename -u

 

TypeName

--------

System.Management.ManagementObject#\Win32_BIOS

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.

PS C:\> gwmi -Property name -Class win32_bios | gm | select typename -u

 

TypeName

--------

System.Management.ManagementObject#\Win32_BIOS

But following the pipeline to the Format-List cmdlet, we no longer have a management object at all. Instead they are all format-related objects as shown here.

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

 

TypeName

--------

Microsoft.PowerShell.Commands.Internal.Format.FormatStartData

Microsoft.PowerShell.Commands.Internal.Format.GroupStartData

Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData

Microsoft.PowerShell.Commands.Internal.Format.GroupEndData

Microsoft.PowerShell.Commands.Internal.Format.FormatEndData

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:

PS C:\> gwmi -Property name, processID -Class win32_Service | Select name, processID

| gm | select typename -u

 

TypeName

--------

Selected.System.Management.ManagementObject

Now, what does this look like when it is displayed to the Windows PowerShell console? The following is a partial output (note that there are no system properties).

PS C:\> gwmi -Property name, processID -Class win32_Service | Select name, processID

 

name                                                                       processID

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

AdobeActiveFileMonitor6.0                                                       2036

AdobeARMservice                                                                 1776

AeLookupSvc                                                                        0

ALG                                                                                0

AppIDSvc                                                                           0

Appinfo                                                                          504

AppMgmt                                                                            0

aspnet_state                                                                       0

AudioEndpointBuilder                                                             456

AudioSrv                                                                         336

AxInstSV                                                                           0

BDESVC                                                                             0

BFE                                                                             1920

BITS                                                                             504

Browser                                                                            0

bthserv                                                                         2796

But what about the object itself? Look at what Get-Member displays. We have created a custom management object with two properties: Name and ProcessID.

PS C:\> gwmi -Property name, processID -Class win32_Service | Select name, processId

| gm

 

   TypeName: Selected.System.Management.ManagementObject

 

Name        MemberType   Definition

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

Equals      Method       bool Equals(System.Object obj)

GetHashCode Method       int GetHashCode()

GetType     Method       type GetType()

ToString    Method       string ToString()

name        NoteProperty System.String name=AdobeActiveFileMonitor6.0

processId   NoteProperty System.UInt32 processId=2036

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.

PS C:\> gwmi -Property name, processID -Class win32_Service | sort name | Select name

, processId -Last 2

 

name                                                                       processId

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

wudfsvc                                                                          456

WwanSvc                                                                            0

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 Split operator 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.

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

gwmi -p $property -cl win32_service | select $property | ft $property –AutoSize

The use of the commands and their associated output is shown here:

Image of command output

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.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed,

    I used this appoach during the last scrippting games, too.

    It is the only reasonable way to get rid of the system properties and it is quit easy to use.

    A switch to accomplish this would be great!

    Klaus.

  • @K_Shulte

    Have you tried this:

    gwmi win32_service | select -expand properties | select name,value

    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.

    Get-CimInstance win32_service | select *

    And OMI is coming. blogs.technet.com/.../open-management-infrastructure.aspx

    I am sure Ed will blog this by the time it is released - October?

  • @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.

  • @Ed -then you will have much bloging to do in October...  YOu shoudl start writing now as we wil have many, may questions.

    Me?  I take some timewith Podh # but too many other things to do so that is slipping.  I suspect you are squirelling away many good secret items....

  • @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 :-)

  • @Ed - good - a new book on PosH 3.

    Have you gotten the documenting workflows yet?  They look to be really neat.

  • @JRV there is some excellent information about workflows on the PowerShell team blog. Work flows are cool ... I would be interested in hearing how you are planning on using them ...