1
votes

Given is a logfile called sample_log.txt which contains sample data of the windows security eventlog. I want to search with a regex pattern for locked out user accounts which is Event ID 4740.

Such a sample looks like this:

Information 22.12.2020 21:28:46 Microsoft-Windows-Security-Auditing 4740    User Account Management "A user account was locked out.

Subject:
    Security ID:        SYSTEM
    Account Name:       SERVER23$
    Account Domain:     DOMAIN
    Logon ID:       0x3E7

Account That Was Locked Out:
    Security ID:        domain\firstname.lastname
    Account Name:       firstname.lastname

I've the following powershell script:

#grab our data
$file = get-content "$PSScriptRoot\sample_log.txt"

#make our pattern

$regex = "Account Name:\s*(\w+).(\w+)"
#loop through each lin
foreach ($line in $file)
{
#if our line contains our pattern, write the matched data to the screen
if($line -match $regex)
{
$matches[0]
}
}

Actually the output would look like this:

 Account Name:      SERVER23
 Account Name:      firstname.lastname

How can I expand/modify the regex pattern if I want only match events with ID 4740 that contains the date and time stamp together with the account name from the sample above?

Thanks in advance for every help and suggestion

1
If the structure is the same, you might use a pattern to check for the presence of the lines and use 2 capturing groups ^.*?\bMicrosoft-Windows-Security-Auditing 4740 .*(?:\r?\n(?!Subject:).*)*\r?\nSubject:(?:\r?\n(?![^\S\r\n]*Account Name:).*)*\r?\n.*Account Name:[^\S\r\n]*(\w+)\$(?:\r?\n(?!Account).*)*\r?\nAccount.*(?:\r?\n(?![^\S\rn]*Account Name:).*)*\r?\n.*Account Name:[^\S\r\n]*(\S+) regex101.com/r/F71XVL/1The fourth bird
If you can go back to the original log, there's a builtin way to get the xml version of the log then access the fields you want.js2010
Why not using the Get-EventLog cmdlet?iRon

1 Answers

1
votes

If the structure of the data is the same, one option is to use a specific pattern checking all lines for the expected values making use of a negative lookahead.

Use -Raw to get the contents of a file as one string.

Capture the value of the account name's in capture group 1 and 2.

^Information \d{2}\.\d{2}\.\d{4} .*? 4740 .*(?:\r?\n(?!Subject:).*)*\r?\nSubject:(?:\r?\n(?![^\S\r\n]*Account Name:).*)*\r?\n.*\b(Account Name:[^\S\r\n]*\w+)\$(?:\r?\n(?!Account).*)*\r?\nAccount.*(?:\r?\n(?![^\S\rn]*Account Name:).*)*\r?\n.*\b(Account Name:[^\S\r\n]*\S+)

The pattern matches

  • ^Information \d{2}\.\d{2}\.\d{4} .*? 4740 .* Match the first line with a "date like" pattern and the number 4740
  • (?:\r?\n(?!Subject:).*)*\r?\n Match the following lines that do not start with Subject:
  • Subject:(?:\r?\n(?![^\S\r\n]*Account Name:).*)*\r?\n Match Subject: followed by matching all lines that do not start with Account name:
  • .*\b(Account Name:[^\S\r\n]*\w+)\$ Capture in group 1 matching Account Name: followed by the spaces and 1+ word chars for the name itself
  • (?:\r?\n(?!Account).*)*\r?\nAccount.*(?:\r?\n(?![^\S\rn]*Account Name:).*)*\r?\n.*\b The same approach for the second part first matching Account, then till Account Name:
  • (Account Name:[^\S\r\n]*\S+) Capture in group 2 matching Account Name: the spaces the account name part itself (using \S+ assuming it can not contain spaces)

Regex demo and a Powershell demo

Example code

$file = Get-Content -Raw sample_log.txt

$regex = '(?m)^Information \d{2}\.\d{2}\.\d{4} .*? 4740 .*(?:\r?\n(?!Subject:).*)*\r?\nSubject:(?:\r?\n(?![^\S\r\n]*Account Name:).*)*\r?\n.*\b(Account Name:[^\S\r\n]*\w+)\$(?:\r?\n(?!Account).*)*\r?\nAccount.*(?:\r?\n(?![^\S\rn]*Account Name:).*)*\r?\n.*\b(Account Name:[^\S\r\n]*\S+)'
Select-String $regex -input $file -AllMatches | Foreach-Object {$_.Matches} | Foreach-Object {
    $_.Groups[1].Value
    $_.Groups[2].Value
}

Output

Account Name:       SERVER23
Account Name:       firstname.lastname