11

I'm writing an error checking script with PowerShell to look over Bitvise SFTP logs and alert if there are any errors. However, I don't want it to alert me on the string "ERROR: Opening Local File" as this is just telling be that the file already exists in the destination, which is expected. I'm not very good with regex and I can't seem to find the right combination of elements to find errors other than the one that we can ignore.

Example:

ERROR: Writing local file  (I want to be alerted to this)
ERROR: Opening local file  (I don't want to be alerted to this)
6
  • 2
    I think you want to research "negative look ahead", but my Regex isn't up to spec so I can't post an answer. – spikey_richie Aug 25 '20 at 15:00
  • 1
    i would likely filter 1st for error:, and then filter for NOT : opening. – Lee_Dailey Aug 25 '20 at 15:03
  • 2
    ^ERROR: [^O]. – Dai Aug 25 '20 at 23:55
  • Soo.. "string starts with ERROR: W" ? – Caius Jard Aug 26 '20 at 9:16
  • Although it's possible (as per the answers given), this is typically a problem solved otherwise - not by regexes. – GrzegorzOledzki Aug 27 '20 at 8:50
14

this seems to do what you want - it uses the way that PoSh can apply a regex match to an entire collection. [grin]

what it does ...

  • creates a sample data set
    when ready to do this for real, replace the entire #region/#endregion block with a Get-Content call.
  • sets the wanted pattern
  • sets the unwanted pattern
  • uses chained regex calls to exclude the unwanted and then to include the wanted
  • assigns that to the $Result collection
  • displays that on screen

the code ...

#region >>> fake reading in a text file
#    in real life, use Get-Content
$InStuff = @'
ERROR: Writing local file  (I want to be alerted to this)
ERROR: Opening local file  (I do not want to be alerted to this)
INFO: Some other thing
ERROR: Yet another thing
INFO: A thing that is wanted
WARNING: Something that may be wanted
'@ -split [System.Environment]::NewLine
#endregion >>> fake reading in a text file

$TargetPattern = 'error:'
$NotWantedPattern = ': opening local file'

$Result = $InStuff -notmatch $NotWantedPattern -match $TargetPattern

$Result

output ...

ERROR: Writing local file  (I want to be alerted to this)
ERROR: Yet another thing
3
  • Although technically not a pure regex answer, this is the solution I went with, so I have marked this as the answer. I wish I could choose both! Thank you! – JJM Aug 25 '20 at 20:33
  • @user1212680 - you are most welcome! glad to have helped a bit ... [grin] – Lee_Dailey Aug 25 '20 at 21:16
  • @Bret - Thanks for the neat edit! you will likely want to make the same "fix the hiliting" edit in the Answer by Hackoo. [grin] – Lee_Dailey Aug 26 '20 at 14:55
40

As @spikey_richie says, you need negative lookahead:

ERROR: (?!Opening local file)

Basically, instead of specifying what you're looking for, you specify what you don't want, and wrap that inside (?! and ).

Demo

6
  • 1
    Ah. I was overcomplicating the regex. This does appear to work. Thanks! Although this did work, I ended up going with Lee's solution. If I had the ability to choose multiple answers, I would. Thank you! – JJM Aug 25 '20 at 20:30
  • 2
    @JJM: you may have prefered the other answer, but to me, this one answers the question you asked more closely and precisely (how to find the lines with the word "ERROR:" but not match "ERROR: opening local file")... So I think it should be the accepted answer (ie, the appropriate answer to the question asked, regardless of what is used in the end by the asker) – Olivier Dulac Aug 26 '20 at 22:49
  • @Glorfindel : maybe put the space within the (?! Opening local file) so that a line without a space after "ERROR:" is also displayed? (the question says to show lines with "ERROR:" (without a space after :) – Olivier Dulac Aug 26 '20 at 22:50
  • 2
    @OlivierDulac, I actually initially did mark this as the answer. But, the hover text to the solution checkmark advises we choose the answer "most helpful in finding our solution." I chose the other as my solution, so I marked it as the answer. – JJM Aug 27 '20 at 22:31
  • 2
    My answer may answer the question better, but the other answer answered the problem better. It makes perfect sense to accept that one, I don't mind at all @JJM. I even got a nice badge for it: superuser.com/help/badges/37/populist?userid=442468 – Glorfindel Aug 28 '20 at 5:20
3

Something like that should work too : Demo

$MyString = @'
ERROR: Writing local file  (I want to be alerted to this)
ERROR: Opening local file  (I don't want to be alerted to this)
INFO: Some other thing
ERROR: Yet another thing
INFO: A thing that is wanted
WARNING: NOT a not-wanted thing
'@ -split [System.Environment]::NewLine

$pattern = 'ERROR: (?!Opening local file).+'
$MyString | %{ [regex]::matches($_,$pattern) } | %{ $_.Groups[0].Value }
0

This situation is similar to those presented in The Greatest Regex Trick Ever --- a great read for anyone learning regex. Whie the negative lookahead posted by Glorfindel works well in this case, this technique is easily expandable to multiple exclusions, lookbehinds combined with lookaheads, etc. and still remain readable. The essence of the trick is to capture all exclusions in the overall match and the desired content in Group 1. For the OP, the regex would look like:

'ERROR: Opening local file|(ERROR:.+$)'

Sample:
(In working code, <Here-string> -Split "`n"
would be replaced by:
Get-Contnet 'c:\Path\To\Error.log' )

@'
ERROR: Another error
ERROR: Writing local file  (I want to be alerted to this)
ERROR: Opening local file  (I don't want to be alerted to this)
THIS is not an error
'@ -Split "`n" | ForEach {
    $_ -match 'ERROR: Opening local file|(ERROR:.+$)' | out-null
    $matches[1]
}

Screen Capture:

PS C:\> @'
>> ERROR: Another error
>> ERROR: Writing local file  (I want to be alerted to this)
>> ERROR: Opening local file  (I don't want to be alerted to this)
>> THIS is not an error
>> '@ -Split "`n" | ForEach {
>>     $_ -match 'ERROR: Opening local file|(ERROR:.+$)' | out-null
>>     $matches[1]
>> }
ERROR: Another error
ERROR: Writing local file  (I want to be alerted to this)
PS C:\>

Again, the beauty of this technique is it's easily expandable: 'Exception1|Exception2|Exception3|(Desired Match)'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.