Use the PowerShell Select-String Cmdlet to Parse WMI Output

Use the PowerShell Select-String Cmdlet to Parse WMI Output

  • Comments 2
  • Likes

Summary: Learn how to use the Windows PowerShell Select-String cmdlet to easily parse WMI output.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I have a quick question: is it possible to parse the output of some of the WMI commands? I know they return objects, but some of the commands return sooooo much data. I would like a quick and easy way to look for specific things such as errors or failures, without a lot of fuss and muss. Is this possible?

—DD

 

Hey, Scripting Guy! AnswerHello DD,

Microsoft Scripting Guy Ed Wilson here. And, yes, it is possible. When working with WMI classes, I normally use the Where-Object cmdlet to perform a filter, or I will use WMI itself to perform the filter. In general, if I am working interactively from the Windows PowerShell prompt, my first choice is to use the Where-Object cmdlet (the alias is ?) simply because it is more natural to me and is easier to type. But it is not as fast. For example, if I am working with the Win32_ReliabilityRecords WMI class, it can return a lot of data. If I am only looking for status messages that contain the word failed in them, I might pipe the results to the Where-Object cmdlet. The command is shown here (gwmi is the alias for the Get-WmiObject cmdlet, and ? is the alias for the Where-Object cmdlet):

gwmi win32_reliabilityrecords | ? { $_.message -match "failed" }

The command and the associated output are shown here.

Image of command and associated output

As you can see in the preceding figure, a lot of information is returned. These are all objects, so I have the opportunity to do additional processing, if I want to do so. However, what if I do not want to do additional processing? In fact, what if all I want to do is see messages that contained the word failed in them? In this case, I might turn to the Select-String cmdlet. The syntax of such a command is shown following this paragraph. This command uses the gwmi alias for the Get-WmiObject cmdlet. There is no default alias for the Select-String cmdlet. In yesterday’s Hey, Scripting Guy! Blog post, I showed how to create an alias called grep to make it easier to use the Select-String cmdlet from an interactive Windows PowerShell prompt.

gwmi win32_reliabilityrecords | select-string "failed" -InputObject {$_.message}

The command and associated output are shown in the following figure.

Image of command and associated output

As shown in the preceding figure, the output is much more succinct and easier to read. So how does the command work? I use the Get-WmiObject cmdlet to query for all records from the Reliability Provider. The Reliability Provider supports the Win32_ReliabilityRecords WMI class. I pipe all of these records to the Select-String cmdlet. The Select-String cmdlet uses the pattern “failed” and searches each incoming message property. Here is the trick: I must use curly brackets along with the $_ automatic variable to read inside the message property. Normally I would use simple parentheses to force the evaluation, but that does not work here. Leaving the inputobject value unadorned does not work either.

What about speed? I decided to use the Measure-Command cmdlet to measure the performance of the two commands. The two commands are shown here:

measure-command {gwmi win32_reliabilityrecords | ? { $_.message -match "failed" } }

measure-command {gwmi win32_reliabilityrecords | select-string "failed" -InputObject {$_.message} }

As seen in the following figure, the first command (using the Where-Object cmdlet) takes about 10.1 seconds. The second command (using the Select-String cmdlet) takes about 10.5 seconds. So the first command is a bit faster.

Image of speed of each command

Unfortunately, the WMI Reliability Provider does not appear to support the WMI like operator. Therefore, the following command fails.

PS C:\> gwmi win32_reliabilityrecords -filter "message -like '%failed%'"

Get-WmiObject : Invalid query

At line:1 char:5

+ gwmi <<<<  win32_reliabilityrecords -filter "message -like '%failed%'"

    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException

    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObject Command

By selecting only the message property, the query speeds a little. The output is better formatted as well:

PS C:\> gwmi win32_reliabilityrecords -Property message | ? {$_.message -match "failed" } 

 

__GENUS          : 2

__CLASS          : Win32_ReliabilityRecords

__SUPERCLASS     :

__DYNASTY        :

__RELPATH        :

__PROPERTY_COUNT : 1

__DERIVATION     : {}

__SERVER         :

__NAMESPACE      :

__PATH           :

Message          : Installation Failure: Windows failed to install the following update with error

                   0x80070643: Definition Update for Windows Defender - KB915597 (Definition 1.99.1

                   460.0).

 

__GENUS          : 2

__CLASS          : Win32_ReliabilityRecords

__SUPERCLASS     :

__DYNASTY        :

__RELPATH        :

__PROPERTY_COUNT : 1

__DERIVATION     : {}

__SERVER         :

__NAMESPACE      :

__PATH           :

Message          : Installation Failure: Windows failed to install the following update with error

                   0x80070643: Definition Update for Microsoft Forefront code named Stirling Beta v

                   ersion - KB977939 (Definition 1.95.257.0).

 

The time of the previous query is shown here:

PS C:\> Measure-command {gwmi win32_reliabilityrecords -Property message | ? {$_.message -match "failed"} } 

 

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 8

Milliseconds      : 911

Ticks             : 89110704

TotalDays         : 0.000103137388888889

TotalHours        : 0.00247529733333333

TotalMinutes      : 0.14851784

TotalSeconds      : 8.9110704

TotalMilliseconds : 8911.0704

 

If I want to return only the message property and not the WMI System properties, I can pipe the results to the Select-Object cmdlet and choose only the message property. This command and associated output are shown here:

PS C:\> gwmi win32_reliabilityrecords -Property message | ? {$_.message -match "failed" } | select message 

message

-------

Installation Failure: Windows failed to install the following update with error 0x80070643: Defi...

Installation Failure: Windows failed to install the following update with error 0x80070643: Defi...

 

As can be seen above, however, the message field is truncated. Therefore, to display the entire message property, it is necessary to use the expandproperty parameter. This is shown here:

PS C:\> gwmi win32_reliabilityrecords -Property message | ? {$_.message -match "failed" } | select -

ExpandProperty message

Installation Failure: Windows failed to install the following update with error 0x80070643: Definit

ion Update for Windows Defender - KB915597 (Definition 1.99.1460.0).

Installation Failure: Windows failed to install the following update with error 0x80070643: Definit

ion Update for Microsoft Forefront code named Stirling Beta version - KB977939 (Definition 1.95.257

.0).

At this point, it is a bit faster and certainly easier to go back to using the Select-String cmdlet. It might make sense to modify it to return only the message property. This revised command and associated output are shown here:

PS C:\> gwmi win32_reliabilityrecords -property message | select-string "failed" -InputObject {$_.me

ssage}

 

Installation Failure: Windows failed to install the following update with error 0x80070643: Definit

ion Update for Windows Defender - KB915597 (Definition 1.99.1460.0).

Installation Failure: Windows failed to install the following update with error 0x80070643: Definit

ion Update for Microsoft Forefront code named Stirling Beta version - KB977939 (Definition 1.95.257

.0).

 

PS C:\>

  

Well, DD, that is about all there is to using the Select-String cmdlet to parse WMI data. Join me tomorrow when we will continue our discussion about parsing output.

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
  • 1) gwmi win32_reliabilityrecords -filter "message like '%failed%'"

    2) gwmi -query "select * from win32_reliabilityrecords  where message like '%failed%'"

    PS 17 >  gwmi win32_reliabilityrecords | measure-object

    Count    : 10065

    Average  :

    Sum      :

    Maximum  :

    Minimum  :

    Property :

    PS 18 >  gwmi win32_reliabilityrecords -filter "message like '%quicktime%'" | measure-object

    Count    : 75

    Average  :

    Sum      :

    Maximum  :

    Minimum  :

    Property :

    PS 19 >  gwmi -query "select * from win32_reliabilityrecords  where message like '%quicktime%'" | Measure-Object

    Count    : 75

    Average  :

    Sum      :

    Maximum  :

    Minimum  :

    Property :

    PS 20 >  Measure-Command { gwmi win32_reliabilityrecords -filter "message like '%quicktime%'"}

    Days              : 0

    Hours             : 0

    Minutes           : 0

    Seconds           : 3

    Milliseconds      : 502

    Ticks             : 35023210

    TotalDays         : 4.05361226851852E-05

    TotalHours        : 0.000972866944444444

    TotalMinutes      : 0.0583720166666667

    TotalSeconds      : 3.502321

    TotalMilliseconds : 3502.321

    PS 21 >  Measure-Command {gwmi -query "select * from win32_reliabilityrecords  where message like '%quicktime%'"}

    Days              : 0

    Hours             : 0

    Minutes           : 0

    Seconds           : 3

    Milliseconds      : 344

    Ticks             : 33447607

    TotalDays         : 3.87125081018519E-05

    TotalHours        : 0.000929100194444444

    TotalMinutes      : 0.0557460116666667

    TotalSeconds      : 3.3447607

    TotalMilliseconds : 3344.7607

  • @Kazum Thanks point that out. Of course, todays article was basically about using Select-String ... Using the -query operator for Get-WmiObject is something most people tend to forget about ... I am glad you brought it up here. Also, I am glad you used Measure-Command to show that -query is MUCH faster ... good comments!