Multiple strings search in consecutive lines in a log file

Viewed 113

I have a log file Input.log which records failed and successful login attempts made by different users and it keeps updating in real time. I am interested only in failed login attempt made by one user i.e. master. Whenever there is a failed login attempt by user master, following 3 fixed text strings will always come in 3 consecutive lines as shown below in sample Input.log file:

Authenticating the user "master" with the password
Failed to logon to the system due to something unexpected
SSCMPE-00102: Failed to authenticate user. Invalid credentials. Enter valid credentials

Input.log file sample for a failed login attempt by master:

[2021-05-14T04:18:41.378-06:00] [FoundationServices0] [NOTIFICATION] [01216] [oracle.bi.bifndnepm.bpmui.logon.CSSAuthenticate] [tid: 30] [userId: <anonymous>] [ecid: 00j8DrPuyNGB1FwDwFj8CW0001hC0004FL,0:1] [APP: WORKSPACE#11.1.2.0] [SRC_CLASS: com.hyperion.bpm.logon.CSSAuthenticate] [SRC_METHOD: authenticateUser:473] Authenticating the user "master" with the password "*********".
[2021-05-14T04:18:41.573-06:00] [FoundationServices0] [ERROR] [02601] [oracle.bi.bifndnepm.bpmui.logon.LogonServlet] [tid: 30] [userId: <anonymous>] [ecid: 00j8DrPuyNGB1FwDwFj8CW0001hC0004FL,0:1] [APP: WORKSPACE#11.1.2.0] [SRC_CLASS: com.hyperion.bpm.logon.LogonServlet] [SRC_METHOD: writeLogonCssException:206] Failed to logon to the system due to something unexpected.[[
SSCMPE-00102: Failed to authenticate user. Invalid credentials. Enter valid credentials.
    at com.hyperion.css.store.identity.IdentityStoreImpl.authenticate(IdentityStoreImpl.java:1845)
    at com.hyperion.css.spi.impl.nvdb.NativeProvider.authenticate(NativeProvider.java:74)
    at com.hyperion.css.facade.impl.CSSAbstractAuthenticator.authenticateUser(CSSAbstractAuthenticator.java:645)
    at com.hyperion.css.facade.impl.CSSAPIAuthenticationImpl.authenticate(CSSAPIAuthenticationImpl.java:69)

I want to create a monitoring script sothat as soon as we have these 3 text strings appeared in 3 consecutive lines, I should get an email alert about the failed login attempt made by user master.

I will schedule the script to run in Windows task scheduler. I'd like to make the script run continuously to detect the failed login attempts in real time. So it should read only freshly written entries in Input.log file from the previous run of the script.

So far I have below code that, in failed.log, gives me all the lines matching above three strings coming consecutively in three lines (what I actually want) but also many other unwanted lines matching the three strings individually in different lines (which I don't want).

$File = "C:\data\Input.log"

$EmailParam=@{
    To='usergroup@domain.com'
    From='user@domain.com'
    SmtpServer='smtp.serveraddress.com'
    Subject='Failed Login Attempt by the user Master'
    Body='Alert! Failed Login Attempt found for the user Master'
    Attachment='failed.log'
}

$String='Authenticating the user "master" with the password','Failed to logon to the system due to something unexpected','SSCMPE-00102: Failed to authenticate user. Invalid credentials. Enter valid credentials'

Get-Content $File | Select-string -Pattern $String | Set-Content failed.log | ForEach {
    Send-MailMessage @EmailParam
}

Would appreciate if you could guide me to fix it. Thanks!

2 Answers

a possible solution: the regex pattern looks at 3 consecutives lines

$pat1 = 'Authenticating the user "master" with the password'
$pat2 = 'Failed to logon to the system due to something unexpected'
$pat2 = 'SSCMPE-00102: Failed to authenticate user. Invalid credentials. Enter valid credentials'
$pat = $pat1 + ".*?`r?`n.*?" + $pat2 + ".*?`r?`n.*?" + $pat3

$path = "C:\Users\ThierryK\Documents\test.log"
$lines = Get-Content -Raw -Path $path 

$option = [System.Text.RegularExpressions.RegexOptions]::Singleline 

$pattern = [regex]::new($pat, $option)

$matches = $pattern.Matches($lines)


foreach($m in $matches){
   $m.Groups[0].Value
   #send your email
}

i suggest you to keep the time each time you scan the log to avoid to scan the same thing every time

$matchingLineCount = 0
$matchingLines = @()

 Get-Content -Wait $File | ForEach-Object {
  if ($matchingLineCount -eq 2) { # 3rd line -> send email.
    $matchingLines += $_
    $matchingLines | Set-Content failed.log
    Send-MailMessage @EmailParam
  }
  elseif ($matchingLineCount -eq 0 -and $_ -match 'Authenticating the user "master"') {
    $matchingLines += $_
    ++$matchingLineCount
    return
  } elseif ($matchingLineCount -eq 1 -and $_ -match 'Failed to logon to the system due to something unexpected') {
    $matchingLines += $_
    ++$matchingLineCount
    return
  }
  $matchingLineCount = 0; $matchingLines = @()
}

Note:

  • Given that only 3 lines must be collected, I'm defining $matchingLines as a regular array (@()) and using += to "append" lines to it, for brevity and convenience.
  • However, in general this approach to iteratively building a collection is inefficient, because every += causes a new array to be created behind the scenes - of necessity, given that arrays are immutable with respect to their element count - see this answer for more information.
    • GitHub issue #5643 discusses switching PowerShell's default collection data structure from non-extensible arrays to an extensible collection type.
Related