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:

  1. A detailed header with synopsis, description, and usage example.
  2. Comments explaining the purpose of each function and its outputs.
  3. Clear and descriptive variable names.
  4. Consistent formatting and indentation for improved readability.
  5. Error handling for critical operations.
  6. A modular structure with separate functions for each major task.
  7. 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.

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 *