Summary: Ed Wilson, Microsoft Scripting Guy, talks about parsing event message strings with Windows PowerShell.
Hey, Scripting Guy! I have seen people using different tools to find stuff in strings in Windows PowerShell, but it always looks complicated. Why is that? I thought Windows PowerShell was supposed to make things easier, but this looks really complicated. Where is the PowerShell advantage in all this?
—BR
Hello BR,
Microsoft Scripting Guy, Ed Wilson, is here. It is about a week away (actually October 28, 2015) that the Scripting Wife (Windows PowerShell MVP, Teresa Wilson) and I will be at the PowerShell user group meeting in Nashville. I will be speaking about data mining with Windows PowerShell, and there are already a bunch of people signed up for this free event. There is limited seating at the Microsoft office in Franklin, so sign up now if you want to attend. I know there will be people from at least five different states at this meeting, so it will be a great time to network with fellow PowerShell geeks. Oh, yeah, here is the sign-up link: Nashville PowerShell User Group: Ed Wilson.
BR, I can certainly understand your frustration, and your question gives me a reason to introduce String Week. There are many ways to parse strings in Windows PowerShell, and some of them are indeed rather complicated—especially for people who did not grow up forming RegEx patterns in their alphabet soup.
Parsing event log messages
One common problem has been parsing the message field of an event log entry. For example, event log entries often contain lots of detailed information in the message field. And although the entry types (Information, Warning, or Error) are generally easy to filter, the Event ID (instanceID) field is easy to filter, and the source of the error is easy to filter, the Message field is often a free form collection of lots of text. This is shown here:
In the past, this meant piping the event log to another cmdlet, such as perhaps Select-String, choosing the message property, and then figuring out the myriad switches and parameters from Select-String. But the Get-EventLog cmdlet has a –Message parameter that accepts a string for a filter. This makes it really easy to filter entries from an event log, based on the text that appears in the message block.
I can ask for an exact match for the text in a message field, but it can become a bit tricky. For example, here I look at the contents of the message field by piping the output to Format-List (fl is an alias):
PS C:\> Get-EventLog -LogName application -Newest 1 | fl *
EventID : 903
MachineName : edLT
Data : {}
Index : 9527
Category : (0)
CategoryNumber : 0
EntryType : 0
Message : The Software Protection service has stopped.
Source : Software Protection Platform Service
ReplacementStrings : {}
InstanceId : 1073742727
TimeGenerated : 10/15/2015 11:23:40 AM
TimeWritten : 10/15/2015 11:23:40 AM
UserName :
Site :
Container :
But as you can see here, when I try to search, it does not find anything:
PS C:\> Get-EventLog -LogName application -Newest 1 -Message "The Software Protection service has stopped."
Get-EventLog : No matches found
At line:1 char:1
+ Get-EventLog -LogName application -Newest 1 -Message "The Software Pr ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-EventLog], ArgumentException
+ FullyQualifiedErrorId : GetEventLogNoEntriesFound,Microsoft.PowerShell.Comman
ds.GetEventLogCommand
When I look at the output closer, it seems that there is something after the end of the string. Maybe a carriage return? The easy way to get around that is to capture the Message property in a variable, and then use that for my search. This is shown here:
PS C:\> $a=(Get-EventLog -LogName application -Newest 1).message
PS C:\> $a
The Software Protection service has stopped.
PS C:\> Get-EventLog -LogName application -Newest 10 -Message "$a"
Index Time EntryType Source InstanceID Message
----- ---- --------- ------ ---------- -------
9527 Oct 15 11:23 0 Software Protecti... 1073742727 The Software...
9455 Oct 15 10:17 0 Software Protecti... 1073742727 The Software...
9442 Oct 15 09:48 0 Software Protecti... 1073742727 The Software...
9398 Oct 15 08:14 0 Software Protecti... 1073742727 The Software...
9387 Oct 15 08:07 0 Software Protecti... 1073742727 The Software...
9285 Oct 14 16:22 0 Software Protecti... 1073742727 The Software...
9200 Oct 14 16:16 0 Software Protecti... 1073742727 The Software...
9084 Oct 14 16:04 0 Software Protecti... 1073742727 The Software...
9048 Oct 14 15:59 0 Software Protecti... 1073742727 The Software...
9004 Oct 14 13:06 0 Software Protecti... 1073742727 The Software...
Use wildcard characters to search
The absolutely, easiest way to search using the –Message property of Get-EventLog is to use a wildcard character. Going back to my original example, I can shortcut all this stuff with a wildcard character. In the following example, I place an asterisk ( * ) at the end of the search string:
PS C:\> Get-EventLog -LogName application -Newest 10 -Message "The Software Protection service has stopped*"
Index Time EntryType Source InstanceID Message
----- ---- --------- ------ ---------- -------
9527 Oct 15 11:23 0 Software Protecti... 1073742727 The Software...
9455 Oct 15 10:17 0 Software Protecti... 1073742727 The Software...
9442 Oct 15 09:48 0 Software Protecti... 1073742727 The Software...
9398 Oct 15 08:14 0 Software Protecti... 1073742727 The Software...
9387 Oct 15 08:07 0 Software Protecti... 1073742727 The Software...
9285 Oct 14 16:22 0 Software Protecti... 1073742727 The Software...
9200 Oct 14 16:16 0 Software Protecti... 1073742727 The Software...
9084 Oct 14 16:04 0 Software Protecti... 1073742727 The Software...
9048 Oct 14 15:59 0 Software Protecti... 1073742727 The Software...
9004 Oct 14 13:06 0 Software Protecti... 1073742727 The Software...
I didn’t type that string in the first place. I simply saw an event that I was interested in, I highlighted it with my mouse, and I pressed ENTER to get that contents into the clipboard. This makes it pretty easy to find similar events in the event log.
But that is all supposing that I know what I want to find. Maybe I am just looking, and I want to find things that failed, for example:
PS C:\> Get-EventLog -LogName application -Newest 10 -Message "*failed*"
Index Time EntryType Source InstanceID Message
----- ---- --------- ------ ---------- -------
9406 Oct 15 09:45 Error Microsoft-Windows... 5973 Activation o...
9365 Oct 14 23:36 Error Microsoft-Windows... 5973 Activation o...
9336 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9334 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9332 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9330 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9328 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9326 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9324 Oct 14 17:28 Error ESENT 488 SettingSyncH...
9322 Oct 14 17:28 Error ESENT 488 SettingSyncH...
In addition to the *, I can use a question mark ( ? ). The ? character is a single letter, meaning that it can be any character in that position. So the following example looks for any three characters, followed by ting followed by anything:
PS C:\> Get-EventLog -LogName application -Newest 10 -Message "???ting*"
Index Time EntryType Source InstanceID Message
----- ---- --------- ------ ---------- -------
9337 Oct 14 17:29 Error ESENT 413 SettingSyncH...
9336 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9335 Oct 14 17:29 Error ESENT 413 SettingSyncH...
9334 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9333 Oct 14 17:29 Error ESENT 413 SettingSyncH...
9332 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9331 Oct 14 17:29 Error ESENT 413 SettingSyncH...
9330 Oct 14 17:29 Error ESENT 488 SettingSyncH...
9329 Oct 14 17:29 Error ESENT 413 SettingSyncH...
9328 Oct 14 17:29 Error ESENT 488 SettingSyncH...
Because I am filtering before I send output, I filter while I am gathering. So the commands are pretty fast and efficient. It is much better than collecting the contents of the event log, and piping it to something else.
Cool. Simple, efficient, and reasonably fast. Looks like a good combination to me.
BR, that is how you can use Select-String to parse strings in PowerShell. String Week will continue tomorrow when I will talk about more cool stuff.
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