opexxx
2/10/2017 - 11:35 PM

Creates a log of changes made to users in AD and emails it out (formatted in HTML) nightly.

Creates a log of changes made to users in AD and emails it out (formatted in HTML) nightly.

#NOTE: MUST be ran as administrator!

<# 
*****************************************************
*                 ADChangesLogger                   *
*****************************************************

Created By: Gunslap
Date Created: June 2nd, 2014

Purpose:
This script will check an AD server for changes and create and email a log.

Requirements:
You must have user logging turned on on the server's event viewer
You must run the script as administrator (to have enough access to read the event viewer)

Potential Issues:
By default the security log has a very small size restriction and depending on how active your network is the log might be completely overwritten
in less than a day. If so, you will have to increase the security log's size drastically if you want run this script (say, weekly) and have it be accurate.
#>

$log_path = "\\Server\e$\LogLocation\" #Location to save .txt log files
$Computer = "ADServer" #AD Server to check the log of
$DateSince = Get-Date
$DateSince = $DateSince.adddays(-7) #How many days into the past to log
$LogName = "ChangeLog_" + ($DateSince).ToString("yyyy-MM-dd") + "_" + $computer #Name of .txt log file
$SearchBase = "DC=Contoso,DC=Com" #Where to search if we need to look up any usernames in AD

#Actual Log Grabber:
$Events = get-eventlog -LogName Security -EntryType SuccessAudit -After $DateSince -ComputerName $Computer `
| where {($_.eventid -eq "5141") -or (($_.eventid -eq "5136") -and ($_.message.Contains("groupPolicyContainer"))) -or ($_.eventid -eq "4720") -or ($_.eventid -eq "4738") -or ($_.eventid -eq "4728") -or ($_.eventid -eq "4729")}

#Quick Test Log Grabber:
#$Events = get-eventlog -LogName Security -Newest 20 -ComputerName $Computer

#Test to just grab from precompiled file:
#$Events = Get-Content -Path "D:\Temp\ChangeLog_Test.txt"

#Create an array to store new message objects:
$FormattedEvents = @()

foreach ($Event in $Events)
{
    $AccountName = ""
    $Description = $Event.Message.split("`n")[0] #The First line of the message has a good summary of what changed.
    $EditedBy = "N/A"
    #Find and Set "Edited By" User (using regex to pull it from the "message" property):
    if($Event.Message -match "Subject:((.|\n)*?)Account Name:\s*\w*")
    {
        $EditedBy = $matches[0]
        if($EditedBy -match "(?<=Account Name:\s*)\w+")
        {
            $EditedBy = $matches[0]
        }
    }
    
    #If it was a "user added to a group" or "User removed from group" event the username is not logged. So we will look it up:
    #It also doesn't display the group they were added to. So we will add it to the description field:
    if ($Event.EventID -eq "4728" -or ($Event.EventID -eq "4729"))
    {
        $SID = $Event.ReplacementStrings[1]
        $AccountName = Get-ADUser -Filter "SID -eq '$SID'" -SearchBase $SearchBase -Server $Computer
        $AccountName = $AccountName.SamAccountName
        if($Event.Message -match "Group:((.|\n)*?)Group Name:\s*\w*")
        {
            $GroupName = $matches[0]
            if($GroupName -match "(?<=Group Name:\s*)\w+")
            {
                $Description += " Group: " + $matches[0]
            }
        }
    }
    #If it was a "User Created" event, we will need to get the account name from the message.
    elseif ($Event.EventID -eq "4720")
    {
        if($Event.Message -match "New Account:((.|\n)*?)Account Name:\s*\w*")
        {
            $AccountName = $matches[0]
            if($AccountName -match "(?<=Account Name:\s*)\w+")
            {
                $AccountName = $matches[0]
            }
        }
    }
    else
    {
        $AccountName = $Event.ReplacementStrings[1]
    }
    #Construct the Object:
    $Properties = @{Time=$Event.TimeGenerated; EventID=$Event.EventID; EventIndex=$Event.Index; AccountName=$AccountName; EditedBy=$EditedBy; MachineName=$Event.MachineName; Description=$Description; Message=$Event.Message}
    $Newobject = New-Object PSObject -Property $Properties
    #Add Event oject to array:
    $FormattedEvents += $NewObject
}

#Output More detailed Logfile:
$FormattedEvents | format-table -AutoSize -Wrap -Property Time, EventID, EventIndex, AccountName, EditedBy, MachineName, Message | Out-File -FilePath ($log_path + $LogName + ".txt") -Width 200

#Construct HTML snippets for email version:
$Head = "<style>"
$Head = $Head + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;font-family:'Arial';}"
$Head = $Head + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;background-color:lightgreen}"
$Head = $Head + "TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;background-color:lightgray}"
$Head = $Head + "</style>"
$Body = "<H2>Active Directory Changes</H2>"
$PostContent = "<p>For further details, please refer to the <a href='" + ($log_path + $LogName + ".txt") + "'>full log</a>.</p>"

#Create the email message body, formatted as as HTML:
$Message = ""
$Message = $FormattedEvents | ConvertTo-HTML -Head $Head -Body $Body -PostContent $PostContent -Property Time, EventID, EventIndex, AccountName, EditedBy, MachineName, Description | Out-String

#Email list of changes made to the helpdesk:
Send-MailMessage -BodyAsHtml -to "administrator@organization.com" -from "no-reply@organization.com" -SmtpServer "smtp.organization.com" -Port 25 -subject ("AD ChangeLog " + (Get-Date)) -Body $Message