Let's start with your revamp with the While
loop... you were so close! When PowerShell evaluates a comparison it uses the type of the left hand object to perform the comparison. In your case you have:
($_ -split ',')[0] -gt $time
Now ($_ -split ',')[0]
is just text, it's a [string]
. It quite likely contains a valid date for the string, but it is still just a string. So PowerShell converts (or at least tries to) $time
to a string, and then does the comparison. If you just reverse it PowerShell will see that $time
is a [datetime]
object, and will try to convert ($_ -split ',')[0]
to be a time object as well, and perform the comparison on two times which is really what you want. What you have may very well work by changing that to:
$time -lt ($_ -split ',')[0]
But wait, there's more!
Your log has timestamps in it, that makes this much better! First get your log as one multi-line string, then split on lines that begin with your timestamp pattern, and parse for times that happened in the last 5 minutes!
$RawLog = Get-Content 'D:......logs...log' -Raw
If($RawLog -split '(?sm)[
](?=d{4}-dd-dd dd:dd:dd)'|Where{[datetime]::Now.AddMinutes(-5) -lt $_.Substring(0,18) -and $_ -match 'Application Error!'}){
$smtp = new-object Net.Mail.SmtpClient("server")
$objMailMessage = New-Object System.Net.Mail.MailMessage
$objMailMessage.From = "[email protected]"
#$objMailMessage.To.Add("[email protected]")
$objMailMessage.To.Add("[email protected]")
$objMailMessage.Subject = "Error message: 'Application error'"
$objMailMessage.Body = "In log in server I traced the following error message: Application error"
$smtp.send($objMailMessage)
}
To break that down a little, we first get the whole log as one long string (with line breaks intact and all that). After that we split the log by looking for either a Carriage Return or New Line character (as represented by [
]
), with a RegEx Look Ahead looking for 4 numbers, a hyphen, 2 numbers, a hyphen, 2 numbers, a space, 2 numbers, colon, 2 numbers, colon, 2 numbers. The way this work is that it removes that new line character, and splits the big string into two parts, then moves on through the second part and keeps doing that splitting it into individual records. For the sample log you provided we end up with 6 records, the last of which is:
2021-01-05 17:07:24
CODE : 00002
LEVEL : 4
NAME : com.apps.common.util.ApplicationException
ERROR # : UTUG12S6W7J0
TOKEN ID : 2574334
USER : 100940297
IP : 10.174.25.221
HOST : xpe1.net
Then we send each of those records through a Where
statement where it checks if the record as a whole matches your search string, and then compares [datetime]::Now.AddMinutes(-5)
, which is a [datetime]
object to $_.Substring(0,18)
, which is the first 18 characters of the current record, or in this case 2021-01-05 17:07:24
. Since the left hand item is a [datetime]
it will try to convert 2021-01-05 17:07:24
to a [datetime]
, which it can totally do, and checks to see if that happened in the last 5 minutes. If any of the records both match the search text, and happened in the last 5 minutes they'll make it past the Where
statement, which makes the If()
evaluate to $true
and it will execute the code in the scriptblock.