Expert Active Directory Monitoring Tool
<# .SYNOPSIS Expert Active Directory Monitoring Tool .DESCRIPTION This script provides comprehensive monitoring and analysis capabilities for on-premises Active Directory environments. It covers various aspects including health checks, security audits, performance analysis, and configuration reviews. .NOTES File Name : ExpertADMonitoringTool.ps1 Author : [Your Name] Prerequisite : PowerShell V5.1 or later, ActiveDirectory, GroupPolicy, and DnsServer modules Version : 1.0 Date : [Current Date] .EXAMPLE .\ExpertADMonitoringTool.ps1 #> # 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 = @() <# .SYNOPSIS Displays the main menu of the tool. #> 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" } <# .SYNOPSIS Performs a comprehensive health check on all domain controllers. .DESCRIPTION This function runs dcdiag tests on all domain controllers to check various aspects of AD health. .OUTPUTS Array of PSObjects containing health check results for each domain controller. #> 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 } <# .SYNOPSIS Performs a security audit of the Active Directory environment. .DESCRIPTION This function checks for various security-related issues such as inactive accounts, non-expiring passwords, empty groups, and dormant computer accounts. .OUTPUTS Array of PSObjects containing security audit 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 } <# .SYNOPSIS Analyzes the performance of domain controllers. .DESCRIPTION This function checks CPU usage, memory usage, and free disk space on all domain controllers. .OUTPUTS Array of PSObjects containing performance metrics for each domain controller. #> 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 } <# .SYNOPSIS Performs replication diagnostics. .DESCRIPTION This function checks for replication failures between domain controllers. .OUTPUTS Array of PSObjects containing replication failure details, if any. #> 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 } <# .SYNOPSIS Checks the health of DNS servers. .DESCRIPTION This function analyzes DNS zones and statistics on all domain controllers. .OUTPUTS Array of PSObjects containing DNS health information for each domain controller. #> 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 } <# .SYNOPSIS Analyzes FSMO roles and site topology. .DESCRIPTION This function identifies FSMO role holders and provides an overview of AD sites and subnets. .OUTPUTS Array of PSObjects containing FSMO role information and site topology details. #> 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 } <# .SYNOPSIS Assesses Group Policy Objects. .DESCRIPTION This function analyzes all GPOs, including their creation time, modification time, and number of settings. .OUTPUTS Array of PSObjects containing GPO assessment results. #> 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 } <# .SYNOPSIS Analyzes user and computer accounts. .DESCRIPTION This function provides statistics on user and computer accounts, including active/inactive counts and OS versions. .OUTPUTS PSObject containing user and computer account analysis results. #> 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 } <# .SYNOPSIS Analyzes Active Directory database and SYSVOL. .DESCRIPTION This function checks the size of NTDS.dit and SYSVOL on each domain controller. .OUTPUTS Array of PSObjects containing AD database and SYSVOL size information for each domain controller. #> 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 } <# .SYNOPSIS Verifies trust relationships. .DESCRIPTION This function checks the health of all trust relationships in the forest. .OUTPUTS Array of PSObjects containing trust relationship status information. #> 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 } <# .SYNOPSIS Checks Active Directory backup status. .DESCRIPTION This function retrieves the last successful backup date for each domain controller. .OUTPUTS Array of PSObjects containing backup status information for each domain controller. #> 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 } <# .SYNOPSIS Generates a comprehensive HTML report. .DESCRIPTION This function compiles all the analysis results into a single HTML report. .OUTPUTS Saves an HTML report to the desktop. #> 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 well-documented script includes:
- A detailed header with synopsis, description, and usage example.
- Comments explaining the purpose of each function and its outputs.
- Clear and descriptive variable names.
- Consistent formatting and indentation for improved readability.
- Error handling for critical operations.
- A modular structure with separate functions for each major task.
- A main program loop that allows users to run individual checks or generate a comprehensive report.
This script is now more maintainable, easier to understand, and can serve as a reference for other administrators or for future modifications. It provides a comprehensive tool for monitoring and analyzing an Active Directory environment, suitable for experienced AD administrators managing complex AD infrastructures.
Leave a Reply
Want to join the discussion?Feel free to contribute!