Introduction to Active Directory and PowerShell
Active Directory (AD) is a crucial component of Microsoft Windows-based networks, providing a directory service that enables centralized management of various network resources. It allows administrators to control user access, manage permissions, and store information related to users, computers, and other devices in a secure and organized manner. AD is essential for maintaining the integrity and security of network environments, especially as organizations grow and diversify their IT resources.
PowerShell, a scripting language and command-line shell, offers a powerful interface for system administrators to interact with Active Directory. It facilitates automation and gives admins the ability to perform complex tasks more efficiently than through the traditional graphical user interface. By utilizing PowerShell, users can simplify routine administrative duties, allowing for quicker responses to potential issues within the network.
Generating reports in Active Directory is a fundamental practice for IT professionals, as it helps monitor various key metrics, including service status, server uptime, and available disk space. The importance of these metrics cannot be overstated, as they play a significant role in preserving the operational health and security of the network environment. Regularly assessing service status ensures that all critical applications are running smoothly, while tracking server uptime helps identify potential reliability issues before they impact users. Additionally, monitoring disk space utilization is vital in preventing performance degradation and avoiding unexpected downtime due to storage constraints.
In this blog post, we will explore how to leverage PowerShell to create detailed reports that encompass these critical metrics, ultimately enhancing your capacity to manage Active Directory effectively.
Creating the Report: PowerShell Scripts for Service Status, Uptime, and Disk Space
I put together a PowerShell script to check Active Directory and all the essential services etc. but included the uptime of the server/s and the free space.
It generates an HTML report that is saved to the “C:\Windows\Temp” directory, feel free to change this to the location you require.
Here is the PowerShell Script, I tested it from Active Directory and Exchange Servers as they have the RSAT tools (Modules) installed:
# Define the list of domain controllers
$domainControllers = Get-ADDomainController -Filter *
# Initialize an array to store the results
$results = @()
foreach ($dc in $domainControllers) {
try {
Write-Verbose "Processing $($dc.HostName)"
$uptime = (Get-WmiObject -Class Win32_OperatingSystem -ComputerName $dc.HostName).LastBootUpTime
$uptimeHours = [math]::Floor(((Get-Date) - [System.Management.ManagementDateTimeConverter]::ToDateTime($uptime)).TotalHours)
$pingStatus = if (Test-Connection -ComputerName $dc.HostName -Count 1 -Quiet) { "Success" } else { "Failed" }
$netlogonService = Get-Service -ComputerName $dc.HostName -Name Netlogon
$ntdsService = Get-Service -ComputerName $dc.HostName -Name NTDS
$dnsServiceStatus = Get-Service -ComputerName $dc.HostName -Name DNS
# Get OS free space percentage
$osDrive = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName $dc.HostName
$freeSpacePercent = [math]::Floor(($osDrive.FreeSpace / $osDrive.Size) * 100)
# Determine uptime color
$uptimeColor = if ($uptimeHours -lt 10) { "background-color: orange;" } elseif ($uptimeHours -gt 730) { "background-color: red; color: white;" } else { "background-color: darkgreen; color: white;" }
# Determine free space color
$freeSpaceColor = if ($freeSpacePercent -lt 10) { "background-color: red; color: white;" } elseif ($freeSpacePercent -lt 15) { "background-color: yellow;" } else { "background-color: darkgreen; color: white;" }
# Run the tests and capture the output
$netlogonsTest = Get-Service -ComputerName $dc.HostName -Name Netlogon 2>&1 | Out-String
$replicationTest = Invoke-Command -ComputerName $dc.HostName -ScriptBlock { dcdiag /test:Replications /s:$($args[0]) } -ArgumentList $dc.HostName 2>&1 | Out-String
$servicesTest = Invoke-Command -ComputerName $dc.HostName -ScriptBlock { dcdiag /test:services /s:$($args[0]) } -ArgumentList $dc.HostName 2>&1 | Out-String
$advertisingTest = Invoke-Command -ComputerName $dc.HostName -ScriptBlock { dcdiag /test:advertising /s:$($args[0]) } -ArgumentList $dc.HostName 2>&1 | Out-String
$fsmoCheckTest = Invoke-Command -ComputerName $dc.HostName -ScriptBlock { dcdiag /test:fsmoCheck /s:$($args[0]) } -ArgumentList $dc.HostName 2>&1 | Out-String
$replicationTestPassed = $replicationTest -notmatch "failed|error"
$servicesTestPassed = $servicesTest -notmatch "failed|error"
$advertisingTestPassed = $advertisingTest -notmatch "failed|error"
$fsmoCheckTestPassed = $fsmoCheckTest -notmatch "failed|error"
$results += [PSCustomObject]@{
Identity = $dc.HostName
Uptime = $uptimeHours
OSFreeSpace = $freeSpacePercent
PingStatus = $pingStatus
NetlogonService = $netlogonService.Status
NTDSService = $ntdsService.Status
DNSServiceStatus = $dnsServiceStatus.Status
ReplicationTest = if ($replicationTestPassed) { "Passed" } else { "Failed" }
ServicesTest = if ($servicesTestPassed) { "Passed" } else { "Failed" }
AdvertisingTest = if ($advertisingTestPassed) { "Passed" } else { "Failed" }
FSMOCheckTest = if ($fsmoCheckTestPassed) { "Passed" } else { "Failed" }
}
} catch {
Write-Error "Failed to process $($dc.HostName): $_"
}
}
# Build the HTML table manually
$html = @"
<html>
<head>
<style>
table { border-collapse: collapse; font-family: Arial; font-size: 8pt; }
th { background-color: lightgrey; color: black; } /* Light grey for heading cells */
th, td { border: 1px solid black; padding: 5px; }
.passed { background-color: darkgreen; color: white; }
.failed { background-color: red; color: white; }
.dc { background-color: lightblue; }
.uptime-orange { background-color: orange; }
.uptime-red { background-color: red; color: white; }
.uptime-green { background-color: darkgreen; color: white; }
.free-space-red { background-color: red; color: white; }
.free-space-yellow { background-color: yellow; }
.free-space-green { background-color: darkgreen; color: white; }
</style>
</head>
<body>
<table>
<tr>
<th>Identity</th>
<th>Uptime (hrs)</th>
<th>OS Free Space %</th>
<th>Ping Status</th>
<th>Netlogon Service</th>
<th>NTDS Service</th>
<th>DNS Service Status</th>
<th>Replication Test</th>
<th>Services Test</th>
<th>Advertising Test</th>
<th>FSMO Check Test</th>
</tr>
"@
foreach ($result in $results) {
$uptimeColor = if ($result.Uptime -lt 10) { "uptime-orange" } elseif ($result.Uptime -gt 730) { "uptime-red" } else { "uptime-green" }
$freeSpaceColor = if ($result.OSFreeSpace -lt 10) { "free-space-red" } elseif ($result.OSFreeSpace -lt 15) { "free-space-yellow" } else { "free-space-green" }
$pingColor = if ($result.PingStatus -eq "Success") { "passed" } else { "failed" }
$netlogonColor = if ($result.NetlogonService -eq "Running") { "passed" } else { "failed" }
$ntdsColor = if ($result.NTDSService -eq "Running") { "passed" } else { "failed" }
$dnsColor = if ($result.DNSServiceStatus -eq "Running") { "passed" } else { "failed" }
$replicationColor = if ($result.ReplicationTest -eq "Passed") { "passed" } else { "failed" }
$servicesColor = if ($result.ServicesTest -eq "Passed") { "passed" } else { "failed" }
$advertisingColor = if ($result.AdvertisingTest -eq "Passed") { "passed" } else { "failed" }
$fsmoColor = if ($result.FSMOCheckTest -eq "Passed") { "passed" } else { "failed" }
$html += "<tr>"
$html += "<td class='dc'>$($result.Identity)</td>"
$html += "<td class='$uptimeColor'>$($result.Uptime)</td>"
$html += "<td class='$freeSpaceColor'>$($result.OSFreeSpace)%</td>"
$html += "<td class='$pingColor'>$($result.PingStatus)</td>"
$html += "<td class='$netlogonColor'>$($result.NetlogonService)</td>"
$html += "<td class='$ntdsColor'>$($result.NTDSService)</td>"
$html += "<td class='$dnsColor'>$($result.DNSServiceStatus)</td>"
$html += "<td class='$replicationColor'>$($result.ReplicationTest)</td>"
$html += "<td class='$servicesColor'>$($result.ServicesTest)</td>"
$html += "<td class='$advertisingColor'>$($result.AdvertisingTest)</td>"
$html += "<td class='$fsmoColor'>$($result.FSMOCheckTest)</td>"
$html += "</tr>"
}
$html += @"
</table>
</body>
</html>
"@
# Save the HTML to a file
$html | Out-File -FilePath "C:\Windows\Temp\ADReport.htm"
Write-Output "HTML report generated: C:\Windows\Temp\ADReport.htm"
Here is a sample output of what the report looks like once it has finished generating: