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:

  1. A comprehensive menu with 13 options
  2. 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
  3. Use of multiple PowerShell modules (ActiveDirectory, GroupPolicy, DnsServer)
  4. 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:

  1. Run PowerShell as an administrator
  2. Have the necessary PowerShell modules installed (ActiveDirectory, GroupPolicy, DnsServer)
  3. Have appropriate permissions in the AD environment (Domain Admin or equivalent)
  4. 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.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *