Home > Powershell > Query Security Log Using Powershell

Query Security Log Using Powershell

I’ve just completed a script that will parse the Windows Security Event log for Event ID’s of type 4624 (user logons).    Once the events have been retrieved the script then creates and outputs a  custom object populated with the following properties:

  • Account Name
  • DateTime
  • Type  ( Interactive,Network,Unlock)

The script is composed of 2 functions:

  • Find-Matches
  • Query-SecurityLog

Query-SecurityLog is the main function and is responsible for creating and outputing the custom object.  Find-Matches is a helper function used to parse the event log message property for the following pattern: “Account Name:      SomeUserName”.    Prior to incorporating the Find-Matches function I had used the -Match operator but then realized that pattern was referenced twice  in the message and that the -Match operator returns only the first matching expression.  So, if you need to find more than one occurrence of a pattern in raw text, you have to switch over to the RegEx object underlying the -Match operator and use it directly.

This left me with 2 possible option that could be used to discover one or more matching values:

  • Select-String (as used in Find-Matches)
  • [regex]

The Find-Matches function was something I already had in my repository of scripts so I went that route, however after reading Chapter 13: Text and Regular Expression in the Powershell.com ebook I realized this could of been done with less code by using [regex].

$Pattern = [regex]"(?i)\baccount name:\s+\w+\b"
$Content = $Pattern.matches($i.message) | select -prop value | %{$_.value}

The example below demonstrates how Select-String is used in the Find-Matches function to output all matching patterns:


I then used an if\else statemtment block to determine  how many matches were returned and then set the $account parameter accordingly.

if($content.Count -eq 2) {
$account = $content[1]} else {$account =  $content }

I was also suprised to see just how many non-user account logon events were recorded and decided to remove any events that referenced the accounts below:

  • System
  • IUSER
  • LOCAL
  • NETWORK
  • $ENV:Computername

As well as filter the events based on the following Logon Types and assign the $logontype variable accordingly:

  • Interactive (2)
  • Network (3)
  • Computer Unlocked (7)

This was done using the following code:

$notmatch = "System|IUSR|LOCAL|NETWORK"
if($account -notmatch $notmatch)  {                        

    if($i.Message | Select-String -Pattern "Logon Type:\s+[2]") {
    $logontype = "Interactive" }
    if($i.Message | Select-String -Pattern "Logon Type:\s+[3]") {
    $logontype = "Network" }
    if($i.Message | Select-String -Pattern "Logon Type:\s+[7]") {
    $logontype = "Computer Unlocked" }
    }

It was then just a matter of creating and populating the custom object.  There are 2 ways to populate an object once created.  One way is to create the object and then use the Add-Member cmdlet to populate it and the other is to use the -Property property along with splatting ( @{} ).

  • $Obj | Add-Member -Noteproperty NameOfProperty  ValueOfProperty
  • -Property @{ NameOfProperty = “Value” }

I choose to go with the Splatting option as it requires less code.

$obj = New-Object PSObject -Property @{
       User = $user
       Date = $Date
       LogonType = $LogonType
       }

The end result was the following code.

Function Find-Matches {                        

 Param($Pattern)
 Process {
  $_ | Select-String -pattern $Pattern -AllMatches |
   select -ExpandProperty matches |
   select -ExpandProperty value
  }
 }                        

Function Query-SecurityLog {               

    Param(
        [int]$MaxEvents,
        [array]$global:Users = @(),
        [string]$Comp = $env:computername,
        $notmatch = "System|IUSR|LOCAL|NETWORK"            

        )                 

    if($MaxEvents)
    { $events = Get-WinEvent -LogName security -MaxEvents $MaxEvents |
    Where-Object{$_.id -eq "4624"}
    } Else {  $events = Get-WinEvent -LogName security  |
    Where-Object{$_.id -eq "4624"}}            

    Foreach($i in $events) {                        

    $content = $i.message| Find-Matches -Pattern "account name:\s+\w+"
    if($content.Count -eq 2) {
    $account = $content[1]} else {$account =  $content }
    $account = (($account -split ":")[1]) -replace "\s+",""                        

    if($account -notmatch $notmatch) {                        

        if($i.Message | Select-String -Pattern "Logon Type:\s+[2]") {
        $logontype = "Interactive" }
        if($i.Message | Select-String -Pattern "Logon Type:\s+[3]") {
        $logontype = "Network" }
        if($i.Message | Select-String -Pattern "Logon Type:\s+[7]") {
        $logontype = "Computer Unlocked" }                        

   $user = $account
   $Date = $i.TimeCreated
   $obj = New-Object PSObject -Property @{
       User = $user
       Date = $Date
       LogonType = $LogonType
       }            

  $Global:Users += $Obj                        

       }
    }                        

 write-output $Global:Users | Select User,Date,LogonType |
             Sort Date -Descending | Format-Table -Auto
}                        

Query-SecurityLog -MaxEvents 1000

The output of Query-SecurityLog  is:

Advertisements
Categories: Powershell Tags:
  1. July 5, 2012 at 11:39 pm

    Nice, but what if you want to know if it was a log on or a log off event? How would you modify it to output the event ID per line?

  2. July 5, 2012 at 11:41 pm

    ..I just realized this only outputs logON events, not off.. It would be handy to have that functionality.

  3. Daragh Owens
    July 11, 2012 at 12:17 pm

    Brilliant it did just what I needed many thanks 🙂
    D.

  4. April 22, 2013 at 3:05 am

    Very shortly this website will be famous among all blogging
    viewers, due to it’s nice posts

    • joeroc
      May 26, 2013 at 3:50 pm

      I appreciate the kind words and look forward to some free time where I can continue to post and contribute to the Powershell community.

  5. June 20, 2013 at 8:24 am

    This is my adaption of your code for use with the Get-Eventlog command. I use this to query remote computers:

    Function Find-Matches {

    Param($Pattern)
    Process {
    $_ | Select-String -pattern $Pattern -AllMatches |
    select -ExpandProperty matches |
    select -ExpandProperty value
    }
    }

    Function Query-SecurityLog {

    Param(
    [int]$MaxEvents,
    [array]$global:Users = @(),
    [string]$Comp = $env:computername,
    $notmatch = “System|IUSR|LOCAL|NETWORK”

    )

    if($MaxEvents)
    { $events = Get-Eventlog security -newest $MaxEvents -Computername 0PCTEST |
    Where-Object {$_.InstanceID -eq “4624”}
    } Else { $events = Get-Eventlog security -Computername 0PCTEST |
    Where-Object {$_.InstanceID -eq “4624”}}

    Foreach($i in $events) {

    $content = $i.message| Find-Matches -Pattern “account name:\s+\w+”
    if($content.Count -eq 2) {
    $account = $content[1]} else {$account = $content }
    $account = (($account -split “:”)[1]) -replace “\s+”,””

    if($account -notmatch $notmatch) {

    if($i.Message | Select-String -Pattern “Logon Type:\s+[2]”) {
    $logontype = “Interactive” }
    if($i.Message | Select-String -Pattern “Logon Type:\s+[3]”) {
    $logontype = “Network” }
    if($i.Message | Select-String -Pattern “Logon Type:\s+[7]”) {
    $logontype = “Computer Unlocked” }

    $user = $account
    $Date = $i.TimeCreated
    $obj = New-Object PSObject -Property @{
    User = $user
    Date = $i.TimeGenerated
    LogonType = $LogonType
    }

    $Global:Users += $Obj

    }
    }

    write-output $Global:Users | Select User,Date,LogonType |
    Sort Date -Descending | Format-Table -Auto
    }

    Query-SecurityLog -MaxEvents 100

  6. henrik
    October 15, 2013 at 9:26 pm

    This goes A LOT faster if you use the filterXML for the eventID.

    code snippet:

    if($MaxEvents)
    {
    $events = Get-WinEvent -MaxEvents $MaxEvents -FilterXML "*[System[(EventID=4624)]]"
    }
    else
    {
    $events = Get-WinEvent -FilterXML "*[System[(EventID=4624)]]"
    }

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: