views:

615

answers:

4

I have the following log entry that I am processing in PowerShell I'm trying to extract all the activity names and durations using the -match operator but I am only getting one match group back. I'm not getting all of the matches that I see when I do the same thing in C# using the Regex object. Can someone explain what I am doing wrong?

Relevant PowerShell Script

$formattedMessage -match "(Get\sClient\sModel|Parse\sExpression|Get\sAbstract\sQuery|Compile\sQuery|Execute\sQuery|Get\sQuery\sPlan\sComplexity|Async\sTotal|Total)\s-\sduration\(([0-9]*)" | out-null
$matches

Output

Name  Value
----  -----
0     Get Client Model - duration(0   
1     Get Client Model
2     0

Log Entry Example:

Timestamp: 11/9/2009 6:48:41 PM
Message: 
Category: QueryService
Priority: 3
EventId: 1001
Severity: Information
Title: SPARQL Query Response
Machine: SPOON16-SERVER
App Domain: KnowledgeBaseHost.exe
ProcessId: 2040
Process Name: D:\QueryService\QSHost.exe
Thread Name: 
Win32 ThreadId:8092
Extended Properties:
Key - Workflow_cbbdd58b-e574-4054-88d4-1dd7a56dc9d9
Timeout - 1800
Result Format - WireTable
Result from Registry - False
Compiled Query from Cache - True
Result Count - 28332
Query Plan Complexity - 661622
Get Client Model - duration(0) start(0)
Parse Expression - duration(0) start(0)
Get Abstract Query - duration(0) start(0)
Compile Query - duration(0) start(0)
Get Query Plan - duration(0) start(1)
Execute Query - duration(63695) start(1)
Get Query Plan Complexity - duration(0) start(63696)
Get Executed Operations - duration(0) start(63696)
Total - duration(63696) start(0)
Async Total - duration(63696) start(0)
A: 

I was able to get all of the groups by defining a Regex and then calling .Matches on that Regex. Still curious to know if this can be done with the -match operator in PowerShell.

$detailRegex = [regex]"(Get\sClient\sModel|Parse\sExpression|Get\sAbstract\sQuery|Compile\sQuery|Execute\sQuery|Get\sQuery\sPlan\sComplexity|Async\sTotal|Total)\s-\sduration\(([0-9]*)"
$detailRegex.Matches($formattedMessage)
spoon16
+3  A: 

You can do this with the Select-String cmdlet in V2 but you need to specify the -AllMatches switch e.g.:

$formattedMessage | Select-String 'regexpattern' -AllMatches

Keep in mind that with the -match operator the primary thing you are doing is looking for "a" match i.e. is the regex pattern matched or not.

Keith Hill
+1  A: 

The -match operator is meant to be used just once; it doesn't do a global match on the input. Keith Hill put a suggestion for a -matchall operator on Microsoft connect here.

I'll suggest another way to do it. If the log entry is in a file, you can use the switch statement to accomplish the same thing:

switch -regex -file .\log.txt { $entryRegex { $matches[1] + ", " + $matches[2] } }

This is the output I get with this statement if $entryRegex has the regular expression you defined:

Get Client Model, 0
Parse Expression, 0
Get Abstract Query, 0
Compile Query, 0
Execute Query, 63695
Get Query Plan Complexity, 0
Total, 63696
Async Total, 63696
Jeff Hillman
+3  A: 

http://www.johndcook.com/regex.html gives a decent example

And, by all means, simplify your expression:

^([^-]+)\s*-\s*duration\(([0-9]+)
  • start at the beginning of the line
  • capture all characters leading up to the first -
  • make sure there's a -
  • skip whitespace
  • make sure the word "duration(" exists
  • capture all digits after "duration("
genio
I tried simplifying the regex as you described (previous to creating the nasty one I have there) and powershell doesn't generate any matches.
spoon16
I took your sample data and was getting proper results with the exact expression above.
genio
powershell will generate matches using the provided regex
James Pogran