Advanced Example 1 - A

This example uses the functions in the module to send an email alert message every time someone is added to the Domain Admins group. The example takes advantage of a few features of the module.

The custom $MailMessageData is created to pass properties to each action that executes. The $MailMessageData object is then in turn stored in another new custom object $MessageData. The $MessageData is passed to Register-EventRecordWrittenEvent, so that it can be referred to within the Action ScriptBlock. This same logic can be used to compile multiple objects into $MessageData, so that all of the information can be available within the Action ScriptBlock for each Event raised. The information can be accessed with the follwowing Syntax:

$MessageData.MailMessageData.From

Next, the example extracts out properties from the Message section of the Event. This is acompmlised with the automatically created XML variable $EventRecordXML. All of the properties can be accessed by navigating the XML ($EventRecordXML.Event.EventData.Data). The example uses XPATH and the SelectSingleNode method to extract out known properties.




$BookmarkToStartFrom = Get-BookmarkToStartFrom

$EventLogQuery = New-EventLogQuery "ForwardedEvents" -query "*[System[(EventID=4728)]]"

$EventLogWatcher = New-EventLogWatcher $EventLogQuery $BookmarkToStartFrom 

$MailMessageData  = new-object psobject -property @{
    'From' = "Event Alert<noreply@YOURDOMAIN.com>";        # Change for your Environment.  Could be changed to a parameter for a script
    'To' = "jdoe<jdoer@YOURDOMAIN.com>";                   # Change for your Environment.  Could be changed to a parameter for a script
    'Subject' = "Domain Admin Added";                      # Change for your Environment.  Could be changed to a parameter for a script
    'SMTPServer' = "smtp.YOURDOMAIN.com";                  # Change for your Environment.  Could be changed to a parameter for a script
}

$MessageData = new-object psobject -property @{
    'MailMessageData' = $MailMessageData
}


$Action = {
            $MemberName = $EventRecordXML.SelectSingleNode("//*[@Name='MemberName']")."#text"
            $MemberSID = $EventRecordXML.SelectSingleNode("//*[@Name='MemberSID']")."#text"
            $TargetUserName = $EventRecordXML.SelectSingleNode("//*[@Name='TargetUserName']")."#text"
            $TargetDomainName = $EventRecordXML.SelectSingleNode("//*[@Name='TargetDomainName']")."#text"
            $TargetSid = $EventRecordXML.SelectSingleNode("//*[@Name='TargetSid']")."#text"
            $SubjectUserSid = $EventRecordXML.SelectSingleNode("//*[@Name='SubjectUserSid']")."#text"
            $SubjectUserName = $EventRecordXML.SelectSingleNode("//*[@Name='SubjectUserName']")."#text"
            $SubjectDomainName = $EventRecordXML.SelectSingleNode("//*[@Name='SubjectDomainName']")."#text"
            $SubjectLogonId = $EventRecordXML.SelectSingleNode("//*[@Name='SubjectLogonId']")."#text"

            If ($TargetUserName -like "*Domain Admins*")
            {
                $From = $MessageData.MailMessageData.From

                $To = $MessageData.MailMessageData.To
                $Subject = $MessageData.MailMessageData.Subject
                $SMTPServer = $MessageData.MailMessageData.SMTPServer
                
                $Body = @" 
The following member was added to the {0} group at {1}:
`
    Member Added: {2}
    Changed By: {3}
    Domain: {4}
`               
"@ -f $TargetuserName, $EventRecord.TimeCreated, $MemberName, $SubjectUserName, $SubjectDomainName
            
            
                
                Send-MailMessage -From $from -To $to -Subject $subject -SmtpServer $SMTPServer -Body $Body
            } #End If
          } #End Action

Register-EventRecordWrittenEvent $EventLogWatcher -action $action -MessageData $MessageData

$EventLogWatcher.Enabled = $True

Advanced Example 1 - B

As an alternative to the XPATH and SelectSingleNode method used in Advanced Example 1 - A, the following logic can be used to create a custom object of all properties under EventData.

$EventObj = New-Object psobject
        
$EventObj = New-Object psobject
$EventObj | Add-Member noteproperty TimeCreated $EventRecord.TimeCreated
$EventObj | Add-Member noteproperty ID $EventRecord.ID
$EventObj | Add-Member noteproperty MachineName $EventRecord.MachineName
        
$EventRecordXML.Event.EventData.Data | Where-Object {$_.name -ne $Null} | ForEach-Object {$EventObj | Add-Member noteproperty $_.name $_."#text"}

The newly created $EventObj can then have the properties accessed in the following manner:

$EventObj.TimeCreated
$EventObj.ID
$EventObj.MemberName
$EventObj.TargetUserName

This can be more useful when the number of properties under EventData for the specific Event ID are unknown. However, it will still be required to call the necessary properties by name.

Advanced Example 2

This example processes all Events in the ForwardedEvents Log, and then outputs specific Event IDs into CSV files. The example uses a custom $BookmarkStreamPath to store the EventBookmark in a specific location. The example also uses a custom SourceIdentifier named "EventsToCSV", this is used to specify a unique name when the Event is registered. SourceIdentifiers need to be unique, so it is important to choose a name other than the default if running more than one EventLogWatcher.

The example focuses on ForwardedEvents from the Security log for Account Management audit events. http://technet.microsoft.com/en-us/library/dd941622(v=WS.10).aspx

Note: If you would like to seperately log Local, Global, and Universal groups, then be sure to change the names of the CSV files accordingly. Also, distribution group Event IDs are not accounted for in this example, along with a number of other Event IDs in this category.

$BookmarkStreamPath = "C:\Eventlogwatchers\EventsToCSV.stream"

$BookmarkToStartFrom = Get-BookmarkToStartFrom $BookmarkStreamPath

$EventLogQuery = New-EventLogQuery "ForwardedEvents"

$EventLogWatcher = New-EventLogWatcher $EventLogQuery $BookmarkToStartFrom 

$Action = {        
            
        
            $EventObj = New-Object psobject
            $EventObj | Add-Member noteproperty TimeCreated $EventRecord.TimeCreated
            $EventObj | Add-Member noteproperty ID $EventRecord.ID
            $EventObj | Add-Member noteproperty MachineName $EventRecord.MachineName
            
            $EventRecordXML.Event.EventData.Data | Where-Object {$_.name -ne $Null} | ForEach-Object {$EventObj | Add-Member noteproperty $_.name $_."#text"}
          
            switch ($EventObj.ID) 
            { 
                # User Account
                4720 {$Outfile = "UserAccount_Created.csv"}
                4722 {$Outfile = "UserAccount_Enabled.csv"}
                4723 {$Outfile = "UserAccount_PWChange.csv"}
                4724 {$Outfile = "UserAccount_PWReset.csv"}
                4725 {$Outfile = "UserAccount_Disabled.csv"}
                4726 {$Outfile = "UserAccount_Deleted.csv"}
                4738 {$Outfile = "UserAccount_Changed.csv"}
                4740 {$Outfile = "UserAccount_Locked.csv"}
                4767 {$Outfile = "UserAccount_Unlocked.csv"}   
                        
                # Global Security Groups     
                4727 {$Outfile = "SecurityGroup_Created.csv"}           
                4728 {$Outfile = "SecurityGroup_MemberAdded.csv"}     
                4729 {$Outfile = "SecurityGroup_MemberRemoved.csv"}  
                4730 {$Outfile = "SecurityGroup_Deleted.csv"}
                4737 {$Outfile = "SecurityGroup_Changed.csv"}        
                
                # Universal Security Groups     
                4754 {$Outfile = "SecurityGroup_Created.csv"}           
                4756 {$Outfile = "SecurityGroup_MemberAdded.csv"}     
                4757 {$Outfile = "SecurityGroup_MemberRemoved.csv"}  
                4758 {$Outfile = "SecurityGroup_Deleted.csv"}   
                4755 {$Outfile = "SecurityGroup_Changed.csv"}
                
                # Local Security Groups     
                4731 {$Outfile = "SecurityGroup_Created.csv"}           
                4732 {$Outfile = "SecurityGroup_MemberAdded.csv"}     
                4733 {$Outfile = "SecurityGroup_MemberRemoved.csv"}  
                4734 {$Outfile = "SecurityGroup_Deleted.csv"}
                4735 {$Outfile = "SecurityGroup_Changed.csv"}  
                
                # Domain Policy
                4739 {$Outfile = "DomainPolicy_Changed.csv"}
                
                # Computer Accounts
                4741 {$Outfile = "ComputerAccount_Created.csv"}
                4742 {$Outfile = "ComputerAccount_Changed.csv"}
                4743 {$Outfile = "ComputerAccount_Deleted.csv"} 
                                
                default {$Outfile = $Null}
            }            
            If ($Outfile -ne $Null)
            {
                $EventObj | Convertto-CSV -Outvariable OutData -NoTypeInformation 
                
                $OutPath = "C:\EventLogWatchers\CSV\$Outfile"
                
                If (Test-Path $OutPath)
                {
                    $Outdata[1..($Outdata.count - 1)] | ForEach-Object {Out-File -InputObject $_ $OutPath -append}
                } else {
                    Out-File -InputObject $Outdata $OutPath
                }
            }

          } 
          
Register-EventRecordWrittenEvent $EventLogWatcher $BookmarkStreamPath -action $action -SourceIdentifier "EventsToCSV"

$EventLogWatcher.Enabled = $True 

Keep in mind that some properties in the EventData section contain multiple lines of information. This is normally "ok", but may cause some confusion when the information is converted into CSV format. An example would be the "User Account Control" property on Event ID 4720. You may choose to flatten the string by removing the newline characters. This can be accomplished using the string replace method.

A rough example is shown below, but the logic has not been added to Example 2 above to avoid extra complexity and confusion in the example.

PS C:\> $Eventobj.UserAccountControl

                %%2080
                %%2082
                %%2084

PS C:\> $Eventobj.UserAccountControl.replace("`n","")
                %%2080          %%2082          %%2084


Last edited Jun 24, 2011 at 9:56 PM by sgrinker, version 13

Comments

sgrinker Aug 30, 2013 at 2:33 PM 
@sprada - Glad to hear that you have found this useful. I apologize as this project really hasn't been updated anymore since I have moved on from the job that had inspired the original need. For that reason I did not see your comment here unti I happened to be on the site today. Take a look at the Documentation section for "Running as a Scheduled Task" and hopefully that will help you out - https://pseventlogwatcher.codeplex.com/wikipage?title=Running%20as%20a%20Scheduled%20Task&referringTitle=Documentation

sprada Apr 15, 2013 at 9:13 AM 
Hello,

Thank you so much for this. Recently discovered this wonderfull project.
Have been using the advanced example 2 daily. However if i try to run it in a schedulke task it does run but it just stops when it reaches the end of the forwarded event log. If I run it in an interactive session (ISE editor for example) it runs as its suposed to. Do you have any ideia why?
Also I've been unable to edit the code to filter for a specific day? Can you help?
My very best regards.