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>"; 'To'="jdoe<jdoer@YOURDOMAIN.com>"; 'Subject'="Domain Admin Added"; 'SMTPServer'="smtp.YOURDOMAIN.com"; } $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