PoshCode Logo PowerShell Code Repository

Get-ADGroupModifications (modification of post by view diff)
embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1402"></script>download | new post

Generates a HTML-report of Active Directory group membership modifications (additions and deletions). Specify a valid path on line 211 to store the report. For more details, see this blog post

  1. ###########################################################################"
  2. #
  3. # NAME: Get-ADGroupModificationsReport.ps1
  4. #
  5. # AUTHOR: Jan Egil Ring
  6. # EMAIL: jan.egil.ring@powershell.no
  7. #
  8. # COMMENT: Generates a HTML-report of Active Directory group membership modifications (addings and deletions).
  9. #          Specify a valid path on line 211 to store the report.
  10. #          For more details, see the following blog-post:
  11. #          http://janegilring.wordpress.com/2009/10/11/active-directory-group-membership-modifications-report
  12. #
  13. # You have a royalty-free right to use, modify, reproduce, and
  14. # distribute this script file in any way you find useful, provided that
  15. # you agree that the creator, owner above has no warranty, obligations,
  16. # or liability for such use.
  17. #
  18. # VERSION HISTORY:
  19. # 1.0 11.10.2009 - Initial release
  20. #
  21. ###########################################################################"
  22.  
  23. #Requires -Version 2.0
  24.  
  25.  
  26. Function Get-CustomHTML ($Header){
  27. $Report = @"
  28. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http`://www.w3.org/TR/html4/frameset.dtd">
  29. <html><head><title>$($Header)</title>
  30. <META http-equiv=Content-Type content='text/html; charset=windows-1252'>
  31.  
  32. <meta name="save" content="history">
  33.  
  34. <style type="text/css">
  35. DIV .expando {DISPLAY: block; FONT-WEIGHT: normal; FONT-SIZE: 10pt; RIGHT: 8px; COLOR: #ffffff; FONT-FAMILY: Tahoma; POSITION: absolute; TEXT-DECORATION: underline}
  36. TABLE {TABLE-LAYOUT: fixed; FONT-SIZE: 100%; WIDTH: 100%}
  37. *{margin:0}
  38. .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}
  39. .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}
  40. .save{behavior:url(#default#savehistory);}
  41. .dspcont1{ display:none}
  42. 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}
  43. 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}
  44. 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}
  45. a.dsphead1 span.dspchar{font-family:monospace;font-weight:normal;}
  46. td {VERTICAL-ALIGN: TOP; FONT-FAMILY: Tahoma}
  47. th {VERTICAL-ALIGN: TOP; COLOR: #cc0000; TEXT-ALIGN: left}
  48. BODY {margin-left: 4pt}
  49. BODY {margin-right: 4pt}
  50. BODY {margin-top: 6pt}
  51. </style>
  52. </head>
  53. <body>
  54. <b><font face="Arial" size="5">$($Header)</font></b><hr size="8" color="#cc0000">
  55. <font face="Arial" size="1"><b>Generated on $($ENV:Computername)</b></font><br>
  56. <font face="Arial" size="1">Report created on $(Get-Date)</font>
  57. <div class="filler"></div>
  58. <div class="filler"></div>
  59. <div class="filler"></div>
  60. <div class="save">
  61. "@
  62. Return $Report
  63. }
  64.  
  65. Function Get-CustomHeader0 ($Title){
  66. $Report = @"
  67.                 <h1><a class="dsphead0">$($Title)</a></h1>
  68.         <div class="filler"></div>
  69. "@
  70. Return $Report
  71. }
  72.  
  73. Function Get-CustomHeader ($Num, $Title){
  74. $Report = @"
  75.         <h2><a class="dsphead$($Num)">
  76.         $($Title)</a></h2>
  77.         <div class="dspcont">
  78. "@
  79. Return $Report
  80. }
  81.  
  82. Function Get-CustomHeaderClose{
  83.  
  84.         $Report = @"
  85.                 </DIV>
  86.                 <div class="filler"></div>
  87. "@
  88. Return $Report
  89. }
  90.  
  91. Function Get-CustomHeader0Close{
  92.  
  93.         $Report = @"
  94. </DIV>
  95. "@
  96. Return $Report
  97. }
  98.  
  99. Function Get-CustomHTMLClose{
  100.  
  101.         $Report = @"
  102. </div>
  103.  
  104. </body>
  105. </html>
  106. "@
  107. Return $Report
  108. }
  109.  
  110. Function Get-HTMLTable {
  111.         param([array]$Content)
  112.         $HTMLTable = $Content | ConvertTo-Html
  113.         $HTMLTable = $HTMLTable -replace "<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN""  ""http`://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"">", ""
  114.         $HTMLTable = $HTMLTable -replace "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN""  ""http`://www.w3.org/TR/html4/strict.dtd"">", ""
  115.         $HTMLTable = $HTMLTable -replace "<html xmlns=""http`://www.w3.org/1999/xhtml"">", ""
  116.         $HTMLTable = $HTMLTable -replace '<html>', ""
  117.         $HTMLTable = $HTMLTable -replace '<head>', ""
  118.         $HTMLTable = $HTMLTable -replace '<title>HTML TABLE</title>', ""
  119.         $HTMLTable = $HTMLTable -replace '</head><body>', ""
  120.         $HTMLTable = $HTMLTable -replace '</body></html>', ""
  121.         Return $HTMLTable
  122. }
  123.  
  124. Function Get-HTMLDetail ($Heading, $Detail){
  125. $Report = @"
  126. <TABLE>
  127.         <tr>
  128.         <th width='25%'><b>$Heading</b></font></th>
  129.         <td width='75%'>$($Detail)</td>
  130.         </tr>
  131. </TABLE>
  132. "@
  133. Return $Report
  134. }
  135.  
  136. function isWithin([int]$days, [datetime]$Date)
  137. {
  138.    [DateTime]::Now.AddDays($days).Date -le $Date.Date
  139. }
  140.  
  141. #Initialize array for domain controllers in the current domain
  142. $domaincontrollers = @()
  143.  
  144. #Get current domain
  145. $dom = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
  146.  
  147. #Get domain controllers in the current domain and add them to the $domain controllers array
  148. $dom.DomainControllers | select Name | ForEach-Object {$domaincontrollers += $_.name}
  149.  
  150.  
  151.  
  152. $MyReport = Get-CustomHTML "Active Directory Group Modifications - Daily Report"
  153.         $MyReport += Get-CustomHeader0 ("$domaincontroller")
  154.                
  155.                 # ---- General Summary Info ----
  156.                 $MyReport += Get-CustomHeader "1" "General Details"
  157.                         $MyReport += Get-HTMLDetail "Domain name:" $dom
  158.                         $MyReport += Get-HTMLDetail "Number of Domain Controllers:" $domaincontrollers.count
  159.                 $MyReport += Get-CustomHeaderClose
  160.  
  161. foreach ($domaincontroller in $domaincontrollers){
  162. # ---- Members added to Domain Local Groups ----
  163.                $MyReport += Get-CustomHeader "1" "Members added to Domain Local Groups on domaincontroller $domaincontroller"
  164.                        $MyReport += Get-HTMLTable (Get-EventLog -LogName 'Security' -ComputerName $domaincontroller | Where-Object {(isWithin -1 $_.TimeWritten) -and $_.EventID -eq "636" -or $_.EventID -eq "4732"} | select TimeGenerated,Message  )
  165.                $MyReport += Get-CustomHeaderClose
  166.  
  167. $MyReport += Get-CustomHeader0Close
  168. $MyReport += Get-CustomHTMLClose
  169.  
  170. # ---- Members removed from Domain Local Groups ----
  171.                $MyReport += Get-CustomHeader "1" "Members removed from Domain Local Groups on domaincontroller $domaincontroller"
  172.                        $MyReport += Get-HTMLTable (Get-EventLog -LogName 'Security' -ComputerName $domaincontroller | Where-Object {(isWithin -1 $_.TimeWritten) -and $_.EventID -eq "637" -or $_.EventID -eq "4733"} | select TimeGenerated,Message  )
  173.                $MyReport += Get-CustomHeaderClose
  174.  
  175. $MyReport += Get-CustomHeader0Close
  176. $MyReport += Get-CustomHTMLClose
  177.  
  178. # ---- Members added to Global Groups ----
  179.                $MyReport += Get-CustomHeader "1" "Members added to Global Groups on domaincontroller $domaincontroller"
  180.                        $MyReport += Get-HTMLTable (Get-EventLog -LogName 'Security' -ComputerName $domaincontroller | Where-Object {(isWithin -1 $_.TimeWritten) -and $_.EventID -eq "632" -or $_.EventID -eq "4728"} | select TimeGenerated,Message  )
  181.                $MyReport += Get-CustomHeaderClose
  182.  
  183. $MyReport += Get-CustomHeader0Close
  184. $MyReport += Get-CustomHTMLClose
  185.  
  186. # ---- Members removed from Global Groups ----
  187.                $MyReport += Get-CustomHeader "1" "Members removed from Global Groups on domaincontroller $domaincontroller"
  188.                        $MyReport += Get-HTMLTable (Get-EventLog -LogName 'Security' -ComputerName $domaincontroller | Where-Object {(isWithin -1 $_.TimeWritten) -and $_.EventID -eq "633" -or $_.EventID -eq "4729"} | select TimeGenerated,Message  )
  189.                $MyReport += Get-CustomHeaderClose
  190.  
  191. $MyReport += Get-CustomHeader0Close
  192. $MyReport += Get-CustomHTMLClose
  193.  
  194. # ---- Members added to Universal Groups ----
  195.                $MyReport += Get-CustomHeader "1" "Members added to Universal Groups on domaincontroller $domaincontroller"
  196.                        $MyReport += Get-HTMLTable (Get-EventLog -LogName 'Security' -ComputerName $domaincontroller | Where-Object {(isWithin -1 $_.TimeWritten) -and $_.EventID -eq "660" -or $_.EventID -eq "4756"} | select TimeGenerated,Message  )
  197.                $MyReport += Get-CustomHeaderClose
  198.  
  199. $MyReport += Get-CustomHeader0Close
  200. $MyReport += Get-CustomHTMLClose
  201.  
  202. # ---- Members removed from Universal Groups ----
  203.                $MyReport += Get-CustomHeader "1" "Members removed from Universal Groups on domaincontroller $domaincontroller"
  204.                        $MyReport += Get-HTMLTable (Get-EventLog -LogName 'Security' -ComputerName $domaincontroller | Where-Object {(isWithin -1 $_.TimeWritten) -and $_.EventID -eq "661" -or $_.EventID -eq "4757"} | select TimeGenerated,Message  )
  205.                $MyReport += Get-CustomHeaderClose
  206.  
  207. $MyReport += Get-CustomHeader0Close
  208. $MyReport += Get-CustomHTMLClose
  209.  
  210. }
  211.  
  212. $Date = Get-Date
  213. $Filename = "C:\Temp\" + "DailyReport" + "_" + $Date.Day + "-" + $Date.Month + "-" + $Date.Year + ".htm"
  214. $MyReport | out-file -encoding ASCII -filepath $Filename

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me