Link to home
Start Free TrialLog in
Avatar of davesnb
davesnbFlag for Canada

asked on

powershell and select-string regex multi line

Hello Ee,

I have the below entries dumped to a text file , the issue is i need to parse through them and filter for ips etc.  Currently, I am unabel to get a good regex for multiline, with the intention of 6 capture groups ( date , Type , method, clientip,username,end) . The end of the entry wil have a "###" and that will be the last capture group .

(\d\/\d\d\/\d\d\d\d\s\d\d:\d\d:\d\d\s..)?(TYPE = .*)?(Method = .*)?(ClientIP = \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?(Username = .*)?(###)?

Open in new window


ideally,Also tried to use the non capture group format " (?:.*\r?\n?)" between the capture groups with no luck, please help .

Once I have a good regex, i can convert to object , run a parse exact on the date and build up an array.


4/28/2017 12:46:46 AM
TYPE = [REQUEST]
Namespace = Company.Test.API
Class = AgencyAccountService
Method = GetCompanyDetails()
ClientIP = 111.111.111.226
CompanyDetailsRequest = <?xml version="1.0" encoding="utf-16"?>
<CompanyDetailsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <AuditKey>00000000-0000-0000-0000-000000000000</AuditKey>
  <CompanyCode>37385670</CompanyCode>
</CompanyDetailsRequest>
Username = SOMEUSER
Cert = 
​
###

Open in new window

Avatar of Rgonzo1971
Rgonzo1971

Hi,

pls try
(\d\/\d\d\/\d\d\d\d\s\d\d:\d\d:\d\d\s..)(?:[\n]*)(TYPE = .*)(?:[\s\S]*?)(Method = .*)(?:[\s\S]*?)(ClientIP = \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:[\s\S]*?)(Username = .*)(?:[\s\S]*?)(###)

Open in new window

Regards
A touch more complex, but it'll get you more than one record.
$pattern = '(?<DateTime>(?:\d{1,2}/){2}\d{2,4} (?:\d{1,2}:){2}\d{1,2} [AP]M)\n' +
         'TYPE = \[(?<Type>[^\]]+)\]\n' +
         '(?:(?:Namespace|Class).+\n){2}' +
         'Method = (?<Method>.+)\n' +
         'ClientIP = (?<ClientIP>(?:\d{1,3}\.){3}\d{1,3})\n' +
         'CompanyDetailsRequest = .+\n' +
         '(?:\s*<.+\n)*' +
         'Username = (?<UserName>\S+)\n'

$regex = New-Object regex($pattern)
if ($regexMatches = $regex.Matches($sample)) {
    foreach ($match in $regexMatches) {
        $result = @{}
        foreach ($name in $regex.GetGroupNames()) {
            $result.$name = $match.Groups[$name].Value
        }
        $result.Remove('0')

        [PSCustomObject]$result
    }
}

Open in new window

SOLUTION
Avatar of Chris Dent
Chris Dent
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I'd use a Switch over that rather than a single regex. Has the advantage that you can convert your text input to the target type right there and then.
$Content = Get-Content -Path C:\Temp\Whatever.txt
$DTProvider = New-Object -TypeName System.Globalization.CultureInfo -ArgumentList 'en-US'
Switch -regex ($Content) {
	'\A\d+/\d+/\d+\s\d+:\d+:\d+\s[A|P]M\Z' {
		$ReturnObject = '' | Select-Object -Property Date, Type, Method, ClientIP, Username
		$ReturnObject.Date = [DateTime]::Parse($_, $DTProvider)
	}
	'\ATYPE\s*=\s*\[(?<Type>.*)\]\Z' {$ReturnObject.Type = $Matches['Type']}
	'\AMethod\s*=\s*(?<Method>.*)\s*\Z' {$ReturnObject.Method = $Matches['Method']}
	'\AClientIP\s*=\s*(?<ClientIP>.*)\s*\Z' {$ReturnObject.ClientIP = $Matches['ClientIP']}
	'\AUsername\s*=\s*(?<Username>.*)\s*\Z' {$ReturnObject.Username = $Matches['Username']}
	'\A###\Z' {$ReturnObject}
}

Open in new window

Avatar of davesnb

ASKER

Thanks guys , so I have a few options there with the regex , as I have been using a convert-textobject and parseexaact for datetime prior so I will go with the more simpler one, but if there are numerous of these entries and I want to store each one into an array ..IS it the  -AllMatches | % { $_.Matches } | % { $_.Value }   ?

$recentlog = gci  C:\Scripts\ClientReports\WIP\APIv3\web13\  -recurse
foreach ($log in $recentlog ) {
$multi += gc $log.fullname 

}
$pattern1 = "(\d\/\d\d\/\d\d\d\d\s\d\d:\d\d:\d\d\s..)(?:[\n]*)(TYPE = .*)(?:[\s\S]*?)(Method = .*)(?:[\s\S]*?)(ClientIP = \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:[\s\S]*?)(Username = .*)(?:[\s\S]*?)(###)"

$logContent1 = $multi| Select-String -pattern $pattern1 -AllMatches | % { $_.Matches } | % { $_.Value }  

Open in new window

Avatar of davesnb

ASKER

Actually , nevermind , I used your Switch -regex ($Content) {

}

and that is pretty slick.. Just needed some time to walk through it as it is very busy..( and i am still catching up to everything it does ) ..;)
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of davesnb

ASKER

Thanks GUys !