Active Directory Monitoring Tool – Expert
# Expert Active Directory Monitoring Tool
# Import required modules
Import-Module ActiveDirectory
Import-Module GroupPolicy
Import-Module DnsServer
# Global variables
$global:reportPath = "$env:USERPROFILE\Desktop\AD_Expert_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').html"
$global:criticalEvents = @()
function Show-Menu {
Clear-Host
Write-Host "=== Expert Active Directory Monitoring Tool ===" -ForegroundColor Cyan
Write-Host "1. Comprehensive Health Check"
Write-Host "2. Security Audit"
Write-Host "3. Performance Analysis"
Write-Host "4. Replication Diagnostics"
Write-Host "5. DNS Health Check"
Write-Host "6. FSMO Roles and Site Topology Analysis"
Write-Host "7. Group Policy Assessment"
Write-Host "8. User and Computer Account Analysis"
Write-Host "9. Active Directory Database and SYSVOL Analysis"
Write-Host "10. Trust Relationship Verification"
Write-Host "11. Active Directory Backup Status"
Write-Host "12. Generate Comprehensive HTML Report"
Write-Host "13. Exit"
}
function Comprehensive-HealthCheck {
Write-Host "`nPerforming Comprehensive Health Check..." -ForegroundColor Yellow
$results = @()
$dcs = Get-ADDomainController -Filter *
foreach ($dc in $dcs) {
$dcdiag = Invoke-Command -ComputerName $dc.HostName -ScriptBlock {
dcdiag /test:services /test:replications /test:advertising /test:fsmocheck /test:ridmanager /test:machineaccount /test:outboundSecureChannels /test:netlogons /test:systemlog /test:kccevent /test:frssysvol /test:frsevent
} -ErrorAction SilentlyContinue
$results += [PSCustomObject]@{
Name = $dc.HostName
Services = if ($dcdiag -match "passed test Services") { "Passed" } else { "Failed" }
Replications = if ($dcdiag -match "passed test Replications") { "Passed" } else { "Failed" }
Advertising = if ($dcdiag -match "passed test Advertising") { "Passed" } else { "Failed" }
FSMORoles = if ($dcdiag -match "passed test FsmoCheck") { "Passed" } else { "Failed" }
RidManager = if ($dcdiag -match "passed test RidManager") { "Passed" } else { "Failed" }
MachineAccount = if ($dcdiag -match "passed test MachineAccount") { "Passed" } else { "Failed" }
OutboundSecureChannels = if ($dcdiag -match "passed test OutboundSecureChannels") { "Passed" } else { "Failed" }
Netlogons = if ($dcdiag -match "passed test NetLogons") { "Passed" } else { "Failed" }
SystemLog = if ($dcdiag -match "passed test SystemLog") { "Passed" } else { "Failed" }
KccEvent = if ($dcdiag -match "passed test KccEvent") { "Passed" } else { "Failed" }
FrsSysVol = if ($dcdiag -match "passed test FrsSysVol") { "Passed" } else { "Failed" }
FrsEvent = if ($dcdiag -match "passed test FrsEvent") { "Passed" } else { "Failed" }
}
}
$results | Format-Table -AutoSize
return $results
}
function Security-Audit {
Write-Host "`nPerforming Security Audit..." -ForegroundColor Yellow
$securityResults = @()
# Check for inactive accounts
$inactiveUsers = Get-ADUser -Filter {Enabled -eq $true} -Properties LastLogonDate | Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-90)}
$securityResults += [PSCustomObject]@{
Check = "Inactive User Accounts"
Result = "$($inactiveUsers.Count) accounts inactive for 90+ days"
}
# Check for accounts with non-expiring passwords
$nonExpiringPasswords = Get-ADUser -Filter {Enabled -eq $true -and PasswordNeverExpires -eq $true} | Measure-Object | Select-Object -ExpandProperty Count
$securityResults += [PSCustomObject]@{
Check = "Non-expiring Passwords"
Result = "$nonExpiringPasswords accounts"
}
# Check for empty groups
$emptyGroups = Get-ADGroup -Filter * | Where-Object {-not (Get-ADGroupMember -Identity $_ -Recursive)} | Measure-Object | Select-Object -ExpandProperty Count
$securityResults += [PSCustomObject]@{
Check = "Empty Groups"
Result = "$emptyGroups groups"
}
# Check for dormant computer accounts
$dormantComputers = Get-ADComputer -Filter {Enabled -eq $true} -Properties LastLogonDate | Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-90)} | Measure-Object | Select-Object -ExpandProperty Count
$securityResults += [PSCustomObject]@{
Check = "Dormant Computer Accounts"
Result = "$dormantComputers accounts inactive for 90+ days"
}
# Check for users with admin rights
$admins = Get-ADGroupMember "Domain Admins" -Recursive | Measure-Object | Select-Object -ExpandProperty Count
$securityResults += [PSCustomObject]@{
Check = "Domain Admins Count"
Result = "$admins users"
}
$securityResults | Format-Table -AutoSize
return $securityResults
}
function Performance-Analysis {
Write-Host "`nPerforming Performance Analysis..." -ForegroundColor Yellow
$perfResults = @()
$dcs = Get-ADDomainController -Filter *
foreach ($dc in $dcs) {
$cpu = Get-WmiObject Win32_Processor -ComputerName $dc.HostName | Measure-Object -Property LoadPercentage -Average | Select-Object -ExpandProperty Average
$memory = Get-WmiObject Win32_OperatingSystem -ComputerName $dc.HostName | Select-Object @{Name="MemoryUsage";Expression={"{0:N2}" -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize)}}
$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $dc.HostName -Filter "DeviceID='C:'" | Select-Object @{Name="FreeSpace";Expression={"{0:N2}" -f ($_.FreeSpace/1GB)}}
$perfResults += [PSCustomObject]@{
Name = $dc.HostName
CPUUsage = "$cpu%"
MemoryUsage = "$($memory.MemoryUsage)%"
FreeDiskSpace = "$($disk.FreeSpace) GB"
}
}
$perfResults | Format-Table -AutoSize
return $perfResults
}
function Replication-Diagnostics {
Write-Host "`nPerforming Replication Diagnostics..." -ForegroundColor Yellow
$replResults = @()
$repl = repadmin /showrepl * /csv | ConvertFrom-Csv
$failedReplications = $repl | Where-Object { $_."Number of Failures" -ne "0" }
if ($failedReplications) {
foreach ($failure in $failedReplications) {
$replResults += [PSCustomObject]@{
SourceDC = $failure."Source DC"
DestinationDC = $failure."Destination DC"
FailureCount = $failure."Number of Failures"
LastFailureTime = $failure."Last Failure Time"
}
}
} else {
$replResults += [PSCustomObject]@{
Status = "No replication failures detected"
}
}
$replResults | Format-Table -AutoSize
return $replResults
}
function DNS-HealthCheck {
Write-Host "`nPerforming DNS Health Check..." -ForegroundColor Yellow
$dnsResults = @()
$dnsServers = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
foreach ($server in $dnsServers) {
$zones = Get-DnsServerZone -ComputerName $server
foreach ($zone in $zones) {
$stats = Get-DnsServerStatistics -ComputerName $server -ZoneName $zone.ZoneName
$dnsResults += [PSCustomObject]@{
Server = $server
Zone = $zone.ZoneName
RecordCount = $zone.ZoneStatistics.RecordCount
Queries = $stats.QueriesReceived
Failures = $stats.QueriesFailure
}
}
}
$dnsResults | Format-Table -AutoSize
return $dnsResults
}
function FSMO-SiteTopologyAnalysis {
Write-Host "`nAnalyzing FSMO Roles and Site Topology..." -ForegroundColor Yellow
$fsmoResults = @()
$forest = Get-ADForest
$domain = Get-ADDomain
$fsmoResults += [PSCustomObject]@{
Role = "Schema Master"
Holder = $forest.SchemaMaster
}
$fsmoResults += [PSCustomObject]@{
Role = "Domain Naming Master"
Holder = $forest.DomainNamingMaster
}
$fsmoResults += [PSCustomObject]@{
Role = "PDC Emulator"
Holder = $domain.PDCEmulator
}
$fsmoResults += [PSCustomObject]@{
Role = "RID Master"
Holder = $domain.RIDMaster
}
$fsmoResults += [PSCustomObject]@{
Role = "Infrastructure Master"
Holder = $domain.InfrastructureMaster
}
$fsmoResults | Format-Table -AutoSize
Write-Host "`nSite Topology:" -ForegroundColor Yellow
$sites = Get-ADReplicationSite -Filter *
foreach ($site in $sites) {
Write-Host "Site: $($site.Name)"
$subnets = Get-ADReplicationSubnet -Filter * | Where-Object {$_.Site -eq $site.DistinguishedName}
foreach ($subnet in $subnets) {
Write-Host " Subnet: $($subnet.Name)"
}
$siteLinks = Get-ADReplicationSiteLink -Filter * | Where-Object {$_.SitesIncluded -contains $site.DistinguishedName}
foreach ($link in $siteLinks) {
Write-Host " Site Link: $($link.Name)"
}
}
return $fsmoResults, $sites
}
function GroupPolicy-Assessment {
Write-Host "`nPerforming Group Policy Assessment..." -ForegroundColor Yellow
$gpoResults = @()
$allGPOs = Get-GPO -All
foreach ($gpo in $allGPOs) {
$report = Get-GPOReport -Guid $gpo.Id -ReportType XML
$settings = ([xml]$report).GPO.Computer.ExtensionData.Extension.Policy | Measure-Object | Select-Object -ExpandProperty Count
$settings += ([xml]$report).GPO.User.ExtensionData.Extension.Policy | Measure-Object | Select-Object -ExpandProperty Count
$gpoResults += [PSCustomObject]@{
Name = $gpo.DisplayName
CreationTime = $gpo.CreationTime
ModificationTime = $gpo.ModificationTime
SettingsCount = $settings
}
}
$gpoResults | Format-Table -AutoSize
return $gpoResults
}
function UserComputer-AccountAnalysis {
Write-Host "`nPerforming User and Computer Account Analysis..." -ForegroundColor Yellow
$users = Get-ADUser -Filter * -Properties LastLogonDate, PasswordLastSet
$computers = Get-ADComputer -Filter * -Properties LastLogonDate, OperatingSystem
$analysis = [PSCustomObject]@{
TotalUsers = $users.Count
ActiveUsers = ($users | Where-Object {$_.Enabled -eq $true}).Count
InactiveUsers = ($users | Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-90)}).Count
PasswordNeverExpires = ($users | Where-Object {$_.PasswordNeverExpires -eq $true}).Count
TotalComputers = $computers.Count
ActiveComputers = ($computers | Where-Object {$_.Enabled -eq $true}).Count
InactiveComputers = ($computers | Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-90)}).Count
Windows10Computers = ($computers | Where-Object {$_.OperatingSystem -like "*Windows 10*"}).Count
Windows11Computers = ($computers | Where-Object {$_.OperatingSystem -like "*Windows 11*"}).Count
ServerComputers = ($computers | Where-Object {$_.OperatingSystem -like "*Server*"}).Count
}
$analysis | Format-List
return $analysis
}
function ADDB-SYSVOLAnalysis {
Write-Host "`nPerforming Active Directory Database and SYSVOL Analysis..." -ForegroundColor Yellow
$dcs = Get-ADDomainController -Filter *
$results = @()
foreach ($dc in $dcs) {
$ntdsPath = Invoke-Command -ComputerName $dc.HostName -ScriptBlock {
(Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters").DatabasePath
}
$ntdsSize = Invoke-Command -ComputerName $dc.HostName -ScriptBlock {
(Get-ChildItem $using:ntdsPath\ntds.dit).Length / 1GB
}
$sysvolSize = Invoke-Command -ComputerName $dc.HostName -ScriptBlock {
(Get-ChildItem C:\Windows\SYSVOL -Recurse | Measure-Object -Property Length -Sum).Sum / 1GB
}
$results += [PSCustomObject]@{
DomainController = $dc.HostName
NTDSSize = "{0:N2} GB" -f $ntdsSize
SYSVOLSize = "{0:N2} GB" -f $sysvolSize
}
}
$results | Format-Table -AutoSize
return $results
}
function Verify-TrustRelationships {
Write-Host "`nVerifying Trust Relationships..." -ForegroundColor Yellow
$trusts = Get-ADTrust -Filter *
$results = @()
foreach ($trust in $trusts) {
$status = Test-ComputerSecureChannel -Server $trust.Name
$results += [PSCustomObject]@{
TrustPartner = $trust.Name
Direction = $trust.Direction
Status = if ($status) { "Healthy" } else { "Unhealthy" }
}
}
$results | Format-Table -AutoSize
return $results
}
function Check-ADBackupStatus {
Write-Host "`nChecking Active Directory Backup Status..." -ForegroundColor Yellow
$dcs = Get-ADDomainController -Filter *
$results = @()
foreach ($dc in $dcs) {
$backupStatus = Invoke-Command -ComputerName $dc.HostName -ScriptBlock {
repadmin /showbackup
}
$lastBackupDate = if ($backupStatus -match "Last successful backup") {
($backupStatus -split "`n" | Select-String "Last successful backup").ToString().Split(":")[1].Trim()
} else {
"No backup information found"
}
$results += [PSCustomObject]@{
DomainController = $dc.HostName
LastBackup = $lastBackupDate
}
}
$results | Format-Table -AutoSize
return $results
}
function Generate-HTMLReport {
Write-Host "`nGenerating Comprehensive HTML Report..." -ForegroundColor Yellow
$reportContent = @"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Active Directory Expert Report</title>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 1200px; margin: 0 auto; padding: 20px; }
h1, h2 { color: #0078D4; }
table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>Active Directory Expert Report</h1>
<p>Generated on: $(Get-Date)</p>
<h2>Comprehensive Health Check</h2>
$($healthCheck | ConvertTo-Html -Fragment)
<h2>Security Audit</h2>
$($securityAudit | ConvertTo-Html -Fragment)
<h2>Performance Analysis</h2>
$($performanceAnalysis | ConvertTo-Html -Fragment)
<h2>Replication Diagnostics</h2>
$($replicationDiagnostics | ConvertTo-Html -Fragment)
<h2>DNS Health Check</h2>
$($dnsHealth | ConvertTo-Html -Fragment)
<h2>FSMO Roles and Site Topology</h2>
$($fsmoAnalysis | ConvertTo-Html -Fragment)
<h2>Group Policy Assessment</h2>
$($gpoAssessment | ConvertTo-Html -Fragment)
<h2>User and Computer Account Analysis</h2>
$($accountAnalysis | ConvertTo-Html -Fragment)
<h2>AD Database and SYSVOL Analysis</h2>
$($dbAnalysis | ConvertTo-Html -Fragment)
<h2>Trust Relationships</h2>
$($trustRelationships | ConvertTo-Html -Fragment)
<h2>AD Backup Status</h2>
$($backupStatus | ConvertTo-Html -Fragment)
</body>
</html>
"@
$reportContent | Out-File -FilePath $global:reportPath
Write-Host "Report generated and saved to: $global:reportPath" -ForegroundColor Green
}
# Main program loop
do {
Show-Menu
$choice = Read-Host "`nEnter your choice (1-13)"
switch ($choice) {
"1" { $healthCheck = Comprehensive-HealthCheck }
"2" { $securityAudit = Security-Audit }
"3" { $performanceAnalysis = Performance-Analysis }
"4" { $replicationDiagnostics = Replication-Diagnostics }
"5" { $dnsHealth = DNS-HealthCheck }
"6" { $fsmoAnalysis = FSMO-SiteTopologyAnalysis }
"7" { $gpoAssessment = GroupPolicy-Assessment }
"8" { $accountAnalysis = UserComputer-AccountAnalysis }
"9" { $dbAnalysis = ADDB-SYSVOLAnalysis }
"10" { $trustRelationships = Verify-TrustRelationships }
"11" { $backupStatus = Check-ADBackupStatus }
"12" { Generate-HTMLReport }
"13" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
}
if ($choice -ne "13") {
Read-Host "`nPress Enter to continue..."
}
} while ($choice -ne "13")
This Expert Active Directory Monitoring Tool includes:
- A comprehensive menu with 13 options
- Advanced functions for various AD monitoring and analysis tasks:
- Comprehensive health check using dcdiag
- Security audit
- Performance analysis of domain controllers
- Replication diagnostics
- DNS health check
- FSMO roles and site topology analysis
- Group Policy assessment
- User and computer account analysis
- AD database and SYSVOL analysis
- Trust relationship verification
- AD backup status check
- Use of multiple PowerShell modules (ActiveDirectory, GroupPolicy, DnsServer)
- Detailed output and reporting capabilities, including HTML report generation
Key features:
- Comprehensive Health Check: Uses dcdiag to perform extensive tests on all domain controllers
- Security Audit: Checks for inactive accounts, non-expiring passwords, empty groups, and more
- Performance Analysis: Monitors CPU, memory, and disk usage on domain controllers
- Replication Diagnostics: Identifies any replication failures across the domain
- DNS Health Check: Verifies DNS zones and statistics
- FSMO Roles and Site Topology: Analyzes FSMO role holders and AD site structure
- Group Policy Assessment: Reviews all GPOs, including creation and modification times
- User and Computer Account Analysis: Provides statistics on user and computer accounts
- AD Database and SYSVOL Analysis: Checks the size of NTDS.dit and SYSVOL on each DC
- Trust Relationships: Verifies the health of all trust relationships
- AD Backup Status: Checks the last successful backup date for each DC
This tool provides a comprehensive analysis of an Active Directory environment. It’s particularly useful for:
- Conducting regular AD health checks
- Preparing for audits
- Troubleshooting complex AD issues
- Capacity planning and performance optimization
- Generating detailed reports for management or compliance purposes
Note: To use this script effectively, you need to:
- Run PowerShell as an administrator
- Have the necessary PowerShell modules installed (ActiveDirectory, GroupPolicy, DnsServer)
- Have appropriate permissions in the AD environment (Domain Admin or equivalent)
- Run this script from a domain-joined machine, preferably a domain controller
This script is suitable for experienced AD administrators who need comprehensive monitoring and analysis capabilities for managing complex Active Directory environments.

Leave a Reply
Want to join the discussion?Feel free to contribute!