Created
February 11, 2019 18:36
-
-
Save SMSAgentSoftware/57aff3513328f56769fb4d0366c987ea to your computer and use it in GitHub Desktop.
Sends an email report with any changes made to Active Directory Sites and Subnets. Run regularly with automation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
###################################################################################### | |
## ## | |
## This script compares the current list of AD sites and subnets with a cached list ## | |
## If anything has changed, the cached list will be updated and the changes emailed ## | |
## ## | |
###################################################################################### | |
################ | |
## PARAMETERS ## | |
################ | |
# Location of cache files | |
$ADSitesFile = "G:\Scheduled Task Scripts\Cache Files\ADSites.csv" | |
$ADSubnetsFile = "G:\Scheduled Task Scripts\Cache Files\ADSubnets.csv" | |
# Email parameters | |
$EmailParams = @{ | |
smtpserver = "contoso-com.mail.protection.outlook.com" | |
To = "[email protected]" | |
From = "[email protected]" | |
Subject = "Active Directory Site and Subnet Changes" | |
} | |
# Html CSS style | |
$Style = @" | |
<style> | |
table { | |
border-collapse: collapse; | |
} | |
td, th { | |
border: 1px solid #ddd; | |
padding: 8px; | |
} | |
th { | |
padding-top: 12px; | |
padding-bottom: 12px; | |
text-align: left; | |
background-color: #4286f4; | |
color: white; | |
} | |
</style> | |
"@ | |
################# | |
## MAIN SCRIPT ## | |
################# | |
# ArrayLists to hold the data | |
$ADSites = [System.Collections.ArrayList]::new() | |
$ADSubnets = [System.Collections.ArrayList]::new() | |
# Retrieve the list of AD sites for the current forest | |
$Sites = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites | |
# Retrieve the AD subnets for each AD site and convert to a custom object | |
foreach ($ADSite in $Sites) | |
{ | |
[void]$ADSites.Add( | |
[PSCustomObject]@{ | |
'AD Site' = $ADSite.Name | |
} | |
) | |
Foreach ($Subnet in $ADSite.Subnets) | |
{ | |
[void]$ADSubnets.Add( | |
[pscustomobject]@{ | |
Name = $Subnet.Name | |
Site = $Subnet.Site | |
Location = $Subnet.Location | |
} | |
) | |
} | |
} | |
# Test whether the cached lists exist, if not create them assuming first run | |
If (!(Test-Path $ADSitesFile)) | |
{ | |
$ADSites | Sort 'AD Site' | Export-Csv -Path $ADSitesFile -NoTypeInformation -Force | |
} | |
If (!(Test-Path $ADSubnetsFile)) | |
{ | |
$ADSubnets | Sort Name | Export-Csv -Path $ADSubnetsFile -NoTypeInformation -Force | |
} | |
# Load in the cached lists | |
$ADSitesCached = Import-Csv -Path $ADSitesFile | |
$ADSubnetsCached = Import-Csv -Path $ADSubnetsFile | |
# More ArrayLists to hold the data | |
$ADSitesAdded = [System.Collections.ArrayList]::new() | |
$ADSitesRemoved = [System.Collections.ArrayList]::new() | |
$ADSubnetsAdded = [System.Collections.ArrayList]::new() | |
$ADSubnetsRemoved = [System.Collections.ArrayList]::new() | |
$ADSubnetsModified = [System.Collections.ArrayList]::new() | |
# New AD sites | |
Foreach ($Item in $ADSites) | |
{ | |
If($Item.'AD Site' -notin $ADSitesCached.'AD Site') | |
{ | |
[void]$ADSitesAdded.Add($Item) | |
} | |
} | |
# Removed AD Sites | |
Foreach ($Item in $ADSitesCached) | |
{ | |
If($Item.'AD Site' -notin $ADSites.'AD Site') | |
{ | |
[void]$ADSitesRemoved.Add($Item) | |
} | |
} | |
# IP subnet where AD Site has changed, or new IP subnet added | |
Foreach ($Item in $ADSubnets) | |
{ | |
$Sub = $ADSubnetsCached.Where({$_.Name -eq $Item.Name}) | |
If ($Sub) | |
{ | |
If ($Sub.Site -ne $Item.Site) | |
{ | |
[void]$ADSubnetsModified.Add( | |
[PSCustomObject]@{ | |
Name = $Item.Name | |
OldSite = $Sub.Site | |
NewSite = $Item.Site | |
} | |
) | |
} | |
} | |
Else | |
{ | |
[void]$ADSubnetsAdded.Add($Item) | |
} | |
} | |
# IP subnet removed | |
Foreach ($Item in $ADSubnetsCached) | |
{ | |
$Sub = $ADSubnets.Where({$_.Name -eq $Item.Name}) | |
If ($Sub){} | |
Else | |
{ | |
[void]$ADSubnetsRemoved.Add($Item) | |
} | |
} | |
# Prepare the HTML | |
If ($ADSitesAdded.Count -ge 1) | |
{ | |
$HTML1 = $ADSitesAdded | | |
ConvertTo-Html -Head $Style -Property 'AD Site' -Body "<h2>The following AD Sites have been ADDED in Active Directory</h2>" -CssUri "http://www.w3schools.com/lib/w3.css" | | |
Out-String | |
} | |
If ($ADSitesRemoved.Count -ge 1) | |
{ | |
$HTML2 = $ADSitesRemoved | | |
ConvertTo-Html -Head $Style -Property 'AD Site' -Body "<h2>The following AD Sites have been REMOVED from Active Directory</h2>" -CssUri "http://www.w3schools.com/lib/w3.css" | | |
Out-String | |
} | |
If ($ADSubnetsAdded.Count -ge 1) | |
{ | |
$HTML3 = $ADSubnetsAdded | | |
ConvertTo-Html -Head $Style -Property Name,Site,Location -Body "<h2>The following IP Subnets have been ADDED in Active Directory</h2>" -CssUri "http://www.w3schools.com/lib/w3.css" | | |
Out-String | |
} | |
If ($ADSubnetsRemoved.Count -ge 1) | |
{ | |
$HTML4 = $ADSubnetsRemoved | | |
ConvertTo-Html -Head $Style -Property Name,Site,Location -Body "<h2>The following IP Subnets have been REMOVED from Active Directory</h2>" -CssUri "http://www.w3schools.com/lib/w3.css" | | |
Out-String | |
} | |
If ($ADSubnetsModified.Count -ge 1) | |
{ | |
$HTML5 = $ADSubnetsModified | | |
ConvertTo-Html -Head $Style -Property Name,OldSite,NewSite -Body "<h2>The AD Site for the following IP Subnets has been MODIFIED in Active Directory</h2>" -CssUri "http://www.w3schools.com/lib/w3.css" | | |
Out-String | |
} | |
$HTML = $HTML1 + $HTML2 + $HTML3 + $HTML4 + $HTML5 | |
# Send the email report and update the cached lists if required | |
If ($HTML.Length -ge 1) | |
{ | |
Try | |
{ | |
Send-MailMessage -Body $HTML @EmailParams -BodyAsHtml -Priority High -ErrorAction Stop | |
} | |
Catch | |
{ | |
$_ | |
Break | |
} | |
$ADSites | Sort 'AD Site' | Export-Csv -Path $ADSitesFile -NoTypeInformation -Force | |
$ADSubnets | Sort Name | Export-Csv -Path $ADSubnetsFile -NoTypeInformation -Force | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment