
Purpose :
Audit Active Directory changes (user/group creation, deletion, changes and GPO changes)
Pre-requesites :
- Windows 2003 or 2008 domain controllers
- Install powershell on the Windows 2003 DCs
- A web site with http,ftp and php features enabled
Powershell script to schedule daily on each Windows 2003 domain controllers :
$log_path = "c:\Temp\" $computer = gc env:computername $result = "result_" + (get-date (get-date).AddDays(-1) -uFormat "%Y-%m-%d") + "_" + $computer + ".log" get-eventlog -LogName Security -After (get-date).adddays(-1) -EntryType SuccessAudit ` | where {($_.eventid -eq "630") -or ($_.eventid -eq "632") -or ($_.eventid -eq "633") -or ($_.eventid -eq "642") -or ($_.eventid -eq "660") -or (($_.eventid -eq "566") -and ($_.message.Contains("f30e3bc2-9ff0-11d1-b603-0000f80367c1")))} ` | Foreach-Object { ($_.timegenerated).tostring() + ";" + ` ($_.eventid).tostring() + ";" + ` $_.username + ";" + ` ((($_.message -replace "`n", ";") -replace ";`t","") -replace "`r","")} ` | Out-File -FilePath ($log_path + $result) -encoding ASCII -append -Width 1000 # Upload using ftp the log results $file = ($log_path + $result) $filenewname = $result $FtpUploadCommand = "PUT `"" + $file + "`""; $FtpCommandFilePath = [System.IO.Path]::GetFullPath("FTPCommand.tmp"); $FtpCommands = @( "ftpuser", "ftppassword", "bin", "quote pasv", $FtpUploadCommand, "quit" ); $FtpCommand = [String]::Join( "`r`n", $FtpCommands ); set-content $FtpCommandFilePath $FtpCommand; ftp "-s:$FtpCommandFilePath" 10.1.1.1; remove-item $FtpCommandFilePath; # Downloaded files removal Remove-Item ($log_path + "*.log")
Powershell script to schedule daily on each Windows 2008 domain controllers :
$log_path = "c:\Temp\" $computer = gc env:computername $result = "result_" + (get-date (get-date).AddDays(-1) -uFormat "%Y-%m-%d") + "_" + $computer + ".log" get-eventlog -LogName Security -After (get-date).adddays(-1) -EntryType SuccessAudit ` | 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")} ` | Foreach-Object { ($_.timegenerated).tostring() + ";" + ` ($_.eventid).tostring() + ";" + ` ((($_.message -replace "`n", ";") -replace ";`t","") -replace "`r",";")}` | Out-File -FilePath ($log_path + $result) -encoding ASCII -append -Width 1000 # Upload using ftp the log results $file = ($log_path + $result) $filenewname = $result $FtpUploadCommand = "PUT `"" + $file + "`""; $FtpCommandFilePath = [System.IO.Path]::GetFullPath("FTPCommand.tmp"); $FtpCommands = @( "ftpuser", "ftppassword", "bin", "quote pasv", $FtpUploadCommand, "quit" ); $FtpCommand = [String]::Join( "`r`n", $FtpCommands ); set-content $FtpCommandFilePath $FtpCommand; ftp "-s:$FtpCommandFilePath" 10.1.1.1; remove-item $FtpCommandFilePath; # Downloaded files removal Remove-Item ($log_path + "*.log")
PHP code to display Active Directory changes (auditad.php) :
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <title>Active Directory Audit</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <link href="index.css" rel="stylesheet" type="text/css"> <LINK REL="SHORTCUT ICON" href="favicon.ico"> </head> <body> <center><table class = "sample"><tr><th> Active Directory Change Audit </table><br><br><br> <table> <form action="<?php echo $url; ?>" method="get" name="myform"> <th><input type="text" name="text_search" value="<?php echo $text_search; ?>" onblur="if(this.value=='') this.value='<?php echo $text_search; ?>';" onfocus="if(this.value=='<?php echo $text_search; ?>') this.value='';"/></th> <th><input type="submit" value="Search" /></th> <th><input name=type type=button value="Show All" onclick="window.open('auditad.php?text_search=All','_self')"/></th> </form> </table> <i><font size=1>(Search criteria : date / event id / change type / modified by) </font> <br><br> <?php //Hide Warning messages error_reporting(0); $folder = "/var/www/dashboard/auditad_log"; $d = array_diff( scandir($folder,1), array(".", "..") ); echo "<TABLE class = \"sample\">"; echo "<TR><TH><font Size=1,5> Date "; echo "<TH><font Size=1,5> Event ID "; echo "<TH><font Size=1,5> Change type "; echo "<TH><font Size=1,5> Modified by "; foreach($d as $filename){ $octet = filesize($folder."/".$filename); if ($octet==0) { continue; } else { $text = file($folder."/".$filename); } $search_string = $_GET['text_search']; if ($search_string == "All" || $search_string == "" || $search_string == null){ $search_string = ""; SearchString($search_string,$text); } else { SearchString($search_string,$text); } } function SearchString($stringtosearch,$text){ $gpolist = "/var/www/dashboard/gpolist.txt"; foreach($text as $line) { if (strpos(strtolower($line),strtolower($stringtosearch))!==false || $stringtosearch == "") { $columns = explode(";", $line); $targetaccount = explode(":", $columns[6]); switch ($columns[1]) { case 4738: $mod_properties = Propmod2008($line); if (strpos($columns[8],"\$")===false && !preg_match("/anonymous/i",$columns[8]) && $mod_properties<>""){ $username = explode(":",$columns[8]); echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>Properties has been changed for $columns[16] <br>$mod_properties"; echo "<TD>$username[1]"; } break; case 4729: $username = explode(":",$columns[8]); echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>$columns[16] has been has been removed from $columns[22]"; echo "<TD>$username[1]"; break; case 4728: $username = explode(":",$columns[8]); echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>$columns[16] has been has been added to $columns[22]"; echo "<TD>$username[1]"; break; case 4720: $username = explode(":",$columns[8]); echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>$columns[16] has been created"; echo "<TD>$username[1]"; break; case 5141: $username = explode(":",$columns[7]); echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>$columns[18] has been deleted"; echo "<TD>$username[1]"; break; case 5136: $username = explode(":",$columns[7]); $gponame = ResolveGPOSID($line,$gpolist); if ($gponame=="" && $columns[6]=="Object Type: %{f30e3bc2-9ff0-11d1-b603-0000f80367c1}"){ echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>The Group policy name cannot be resolved. Please update the configuration file gpolist.txt"; echo "<TD>$username[1]"; } elseif ($gponame<>"") { echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>GPO $gponame has been modified"; echo "<TD>$username[1]"; } break; case 566: $gpoguid = explode("%", $columns[7]); $gpoguid_mod = str_replace('}','',str_replace('{','',$gpoguid[1])); $gponame = ResolveGPOGUID($gpoguid_mod,$gpolist); if ($gponame=="" && $columns[6]=="Object Type: %{f30e3bc2-9ff0-11d1-b603-0000f80367c1}"){ echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>The Group policy name cannot be resolved. Please update the configuration file gpolist.txt"; echo "<TD>$columns[2]"; } elseif ($gponame<>"") { echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>GPO $gponame has been modified"; echo "<TD>$columns[2]"; } break; case 630: echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; $accountdeleted = explode(":", $columns[4]); echo "<TD>$accountdeleted[1] has been deleted"; echo "<TD>$columns[2]"; break; case 660: echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; if ($columns[3]=="Member Name: -"){ echo "<TD>Primary group $columns[7] has been set for user $columns[4]"; } else { echo "<TD>$columns[4] has been added to $targetaccount[1] group"; } echo "<TD>$columns[2]"; break; case 632: echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; if ($columns[3]=="Member Name: -"){ echo "<TD>Primary group $columns[7] has been set for user $columns[4]"; } else { echo "<TD>$columns[4] has been added to $targetaccount[1] group"; } echo "<TD>$columns[2]"; break; case 633: echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; if ($columns[3]=="Member Name: -"){ echo "<TD>Primary group $columns[7] has been removed for user $columns[4]"; } else { echo "<TD>$columns[4] has been removed from $targetaccount[1] group"; } echo "<TD>$columns[2]"; break; case 642: $mod_properties = Propmod($line); if (strpos($columns[2],"\$")===false && !preg_match("/anonymous/i",$columns[2]) && $mod_properties<>""){ echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>Properties has been changed for $columns[4] <br>$mod_properties"; echo "<TD>$columns[2]"; } elseif (strpos($columns[2],"\$")===false && $columns[18]=="Password Last Set: <never>" ){ echo "<TR><TD>$columns[0]"; echo "<TD>$columns[1]"; echo "<TD>User account created : $columns[5]"; echo "<TD>$columns[2]"; } break; default: } } } } $d->close(); function Propmod2008($event){ $result = ""; for ($i=22;$i<41;$i++) { $field = explode(";", $event); $field_prop = explode(':',$field[$i]); $field_prop_clean = trim($field_prop[1]); if ($field_prop_clean<>"-" && $result=="") { $result = $field[$i]; } elseif ($field_prop_clean<>"-" && $result<>"") { $result = $result."<br>".$field[$i]; } } return $result; } function Propmod($event){ $result = ""; for ($i=13;$i<28;$i++) { $field = explode(";", $event); $field_prop = explode(":\t",$field[$i]); if ($field_prop[1]<>"-" && $result=="") { $result = $field[$i]; } elseif ($field_prop[1]<>"-" && $result<>"") { $result = $result."<br>".$field[$i]; } } return $result; } function ResolveGPOGUID($GUID,$gpo_list){ $gpotext = file($gpo_list); foreach($gpotext as $gpoline) { $columns = explode(";", $gpoline); if ($columns[1] <> $GUID) { continue; } else { return $columns[2]; } } } function ResolveGPOSID($SID,$gpo_list){ $gpotext = file($gpo_list); foreach($gpotext as $gpoline) { $columns = explode(";", $gpoline); if (strpos($SID,$columns[0])) { return $columns[2]; } else { continue; } } } ?>
My Powershell script categories
- Active Directory
- Cluster
- Database
- Exchange
- Files and folders
- Hardware
- Network
- Operating System
- PKI
- SCCM
- Service and process
- Tips
- VMWare
Audit Active Directory changes
I every time spent my half an hour to read this web site’s content every day along with a cup of coffee.