﻿# encoding: utf-8
# api: powershell
# title: Get-ADGroupModifications
# description: The Get-ADGroupModificationsReport script, which were posted on http://poshcode.org/1402, are now enhanced in due to performance by storing each domain controllers security eventlog in a variable
# version: 4.01
# type: script
# author: Jan Egil Ring
# license: CC0
# function: Get-CustomHTML
# x-poshcode-id: 1810
# x-archived: 2017-03-27T02:33:52
# x-published: 2011-04-29T07:54:00
#
#
###########################################################################"
#
# NAME: Get-ADGroupModificationsReport.ps1
#
# AUTHOR: Jan Egil Ring
# EMAIL: jan.egil.ring@powershell.no
#
# COMMENT: Generates a HTML-report of Active Directory group membership modifications (addings and deletions). 
#          Specify a valid path on line 211 to store the report.
#          For more details, see the following blog-post: 
#          http://blog.powershell.no/2009/10/11/active-directory-group-membership-modifications-report
#
# You have a royalty-free right to use, modify, reproduce, and
# distribute this script file in any way you find useful, provided that
# you agree that the creator, owner above has no warranty, obligations,
# or liability for such use.
#
# VERSION HISTORY:
# 1.0 11.10.2009 - Initial release
# 1.1 29.04.2010 - Enhanced the script performance by storing each domain controllers security eventlog in a variable
#
###########################################################################"

#Requires -Version 2.0


function Get-CustomHTML ($Header){
$Report = @"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http`://www.w3.org/TR/html4/frameset.dtd">
<html><head><title>$($Header)</title>
<META http-equiv=Content-Type content='text/html; charset=windows-1252'>

<meta name="save" content="history">

<style type="text/css">
DIV .expando {DISPLAY: block; FONT-WEIGHT: normal; FONT-SIZE: 10pt; RIGHT: 8px; COLOR: #ffffff; FONT-FAMILY: Tahoma; POSITION: absolute; TEXT-DECORATION: underline}
TABLE {TABLE-LAYOUT: fixed; FONT-SIZE: 100%; WIDTH: 100%}
*{margin:0}
.dspcont { BORDER-RIGHT: #bbbbbb 1px solid; BORDER-TOP: #bbbbbb 1px solid; PADDING-LEFT: 16px; FONT-SIZE: 8pt;MARGIN-BOTTOM: -1px; PADDING-BOTTOM: 5px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; WIDTH: 95%; COLOR: #000000; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; BACKGROUND-COLOR: #f9f9f9}
.filler {BORDER-RIGHT: medium none; BORDER-TOP: medium none; DISPLAY: block; BACKGROUND: none transparent scroll repeat 0% 0%; MARGIN-BOTTOM: -1px; FONT: 100%/8px Tahoma; MARGIN-LEFT: 43px; BORDER-LEFT: medium none; COLOR: #ffffff; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: medium none; POSITION: relative}
.save{behavior:url(#default#savehistory);}
.dspcont1{ display:none}
a.dsphead0 {BORDER-RIGHT: #bbbbbb 1px solid; PADDING-RIGHT: 5em; BORDER-TOP: #bbbbbb 1px solid; DISPLAY: block; PADDING-LEFT: 5px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; MARGIN-BOTTOM: -1px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; CURSOR: hand; COLOR: #FFFFFF; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; HEIGHT: 2.25em; WIDTH: 95%; BACKGROUND-COLOR: #cc0000}
a.dsphead1 {BORDER-RIGHT: #bbbbbb 1px solid; PADDING-RIGHT: 5em; BORDER-TOP: #bbbbbb 1px solid; DISPLAY: block; PADDING-LEFT: 5px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; MARGIN-BOTTOM: -1px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; CURSOR: hand; COLOR: #ffffff; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; HEIGHT: 2.25em; WIDTH: 95%; BACKGROUND-COLOR: #7BA7C7}
a.dsphead2 {BORDER-RIGHT: #bbbbbb 1px solid; PADDING-RIGHT: 5em; BORDER-TOP: #bbbbbb 1px solid; DISPLAY: block; PADDING-LEFT: 5px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; MARGIN-BOTTOM: -1px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; CURSOR: hand; COLOR: #ffffff; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; HEIGHT: 2.25em; WIDTH: 95%; BACKGROUND-COLOR: #A5A5A5}
a.dsphead1 span.dspchar{font-family:monospace;font-weight:normal;}
td {VERTICAL-ALIGN: TOP; FONT-FAMILY: Tahoma}
th {VERTICAL-ALIGN: TOP; COLOR: #cc0000; TEXT-ALIGN: left}
BODY {margin-left: 4pt} 
BODY {margin-right: 4pt} 
BODY {margin-top: 6pt} 
</style>
</head>
<body>
<b><font face="Arial" size="5">$($Header)</font></b><hr size="8" color="#cc0000">
<font face="Arial" size="1"><b>Generated on $($ENV:Computername)</b></font><br>
<font face="Arial" size="1">Report created on $(Get-Date)</font>
<div class="filler"></div>
<div class="filler"></div>
<div class="filler"></div>
<div class="save">
"@
return $Report
}

function Get-CustomHeader0 ($Title){
$Report = @"
		<h1><a class="dsphead0">$($Title)</a></h1>
	<div class="filler"></div>
"@
return $Report
}

function Get-CustomHeader ($Num, $Title){
$Report = @"
	<h2><a class="dsphead$($Num)">
	$($Title)</a></h2>
	<div class="dspcont">
"@
return $Report
}

function Get-CustomHeaderClose{

	$Report = @"
		</DIV>
		<div class="filler"></div>
"@
return $Report
}

function Get-CustomHeader0Close{

	$Report = @"
</DIV>
"@
return $Report
}

function Get-CustomHTMLClose{

	$Report = @"
</div>

</body>
</html>
"@
return $Report
}

function Get-HTMLTable {
	param([array]$Content)
	$HTMLTable = $Content | ConvertTo-Html
	$HTMLTable = $HTMLTable -replace "<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN""  ""http`://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"">", ""
	$HTMLTable = $HTMLTable -replace "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN""  ""http`://www.w3.org/TR/html4/strict.dtd"">", ""
	$HTMLTable = $HTMLTable -replace "<html xmlns=""http`://www.w3.org/1999/xhtml"">", ""
	$HTMLTable = $HTMLTable -replace '<html>', ""
	$HTMLTable = $HTMLTable -replace '<head>', ""
	$HTMLTable = $HTMLTable -replace '<title>HTML TABLE</title>', ""
	$HTMLTable = $HTMLTable -replace '</head><body>', ""
	$HTMLTable = $HTMLTable -replace '</body></html>', ""
	return $HTMLTable
}

function Get-HTMLDetail ($Heading, $Detail){
$Report = @"
<TABLE>
	<tr>
	<th width='25%'><b>$Heading</b></font></th>
	<td width='75%'>$($Detail)</td>
	</tr>
</TABLE>
"@
return $Report
}

#Initialize array for domain controllers in the current domain
$domaincontrollers = @()

#Get current domain
$dom = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()

#Get domain controllers in the current domain and add them to the $domain controllers array
$dom.DomainControllers | select Name | ForEach-Object {$domaincontrollers += $_.name}



$MyReport = Get-CustomHTML "Active Directory Group Modifications - Daily Report"
	$MyReport += Get-CustomHeader0 ("$domaincontroller")
		
		# ---- General Summary Info ----
		$MyReport += Get-CustomHeader "1" "General Details"
			$MyReport += Get-HTMLDetail "Domain name:" $dom
			$MyReport += Get-HTMLDetail "Number of Domain Controllers:" $domaincontrollers.count
		$MyReport += Get-CustomHeaderClose

foreach ($domaincontroller in $domaincontrollers){

$eventlog = Get-EventLog -LogName �Security� -ComputerName $domaincontroller -After ((Get-Date).AddDays(-1))

# ---- Members added to Domain Local Groups ----
                $MyReport += Get-CustomHeader "1" "Members added to Domain Local Groups on domaincontroller $domaincontroller"
                        $MyReport += Get-HTMLTable ($eventlog | Where-Object {$_.EventID -eq "636" -or $_.EventID -eq "4732"} | select TimeGenerated,Message  )
                $MyReport += Get-CustomHeaderClose

$MyReport += Get-CustomHeader0Close
$MyReport += Get-CustomHTMLClose

# ---- Members removed from Domain Local Groups ----
                $MyReport += Get-CustomHeader "1" "Members removed from Domain Local Groups on domaincontroller $domaincontroller"
                        $MyReport += Get-HTMLTable ($eventlog | Where-Object {$_.EventID -eq "637" -or $_.EventID -eq "4733"} | select TimeGenerated,Message  )
                $MyReport += Get-CustomHeaderClose

$MyReport += Get-CustomHeader0Close
$MyReport += Get-CustomHTMLClose

# ---- Members added to Global Groups ----
                $MyReport += Get-CustomHeader "1" "Members added to Global Groups on domaincontroller $domaincontroller"
                        $MyReport += Get-HTMLTable ($eventlog | Where-Object {$_.EventID -eq "632" -or $_.EventID -eq "4728"} | select TimeGenerated,Message  )
                $MyReport += Get-CustomHeaderClose

$MyReport += Get-CustomHeader0Close
$MyReport += Get-CustomHTMLClose

# ---- Members removed from Global Groups ----
                $MyReport += Get-CustomHeader "1" "Members removed from Global Groups on domaincontroller $domaincontroller"
                        $MyReport += Get-HTMLTable ($eventlog | Where-Object {$_.EventID -eq "633" -or $_.EventID -eq "4729"} | select TimeGenerated,Message  )
                $MyReport += Get-CustomHeaderClose

$MyReport += Get-CustomHeader0Close
$MyReport += Get-CustomHTMLClose

# ---- Members added to Universal Groups ----
                $MyReport += Get-CustomHeader "1" "Members added to Universal Groups on domaincontroller $domaincontroller"
                        $MyReport += Get-HTMLTable ($eventlog | Where-Object {$_.EventID -eq "660" -or $_.EventID -eq "4756"} | select TimeGenerated,Message  )
                $MyReport += Get-CustomHeaderClose

$MyReport += Get-CustomHeader0Close
$MyReport += Get-CustomHTMLClose

# ---- Members removed from Universal Groups ----
                $MyReport += Get-CustomHeader "1" "Members removed from Universal Groups on domaincontroller $domaincontroller"
                        $MyReport += Get-HTMLTable ($eventlog | Where-Object {$_.EventID -eq "661" -or $_.EventID -eq "4757"} | select TimeGenerated,Message  )
                $MyReport += Get-CustomHeaderClose

$MyReport += Get-CustomHeader0Close
$MyReport += Get-CustomHTMLClose

}

$Date = Get-Date
$Filename = "C:\Temp\" + "DailyReport" + "_" + $Date.Day + "-" + $Date.Month + "-" + $Date.Year + ".htm"
$MyReport | out-file -encoding ASCII -filepath $Filename
