Table of Contents

Overview

Active Directory troubleshooting requires a systematic approach to identify and resolve issues affecting authentication, replication, DNS, and service functionality. This guide provides diagnostic procedures and solutions for common AD problems.

Diagnostic Tools

Built-in Windows Tools

Essential tools for AD troubleshooting:

# Domain Controller Diagnostics
dcdiag /c /v /f:dcdiag-results.txt

# Replication Diagnostics
repadmin /showrepl
repadmin /replsummary
repadmin /syncall /AdeP

# DNS Diagnostics
nslookup -type=SRV _ldap._tcp.dc._msdcs.domain.com
dcdiag /test:dns /v

# Network and Authentication
nltest /dsgetdc:domain.com
nltest /sc_query:domain.com
w32tm /query /status

# Event Log Analysis
Get-WinEvent -LogName "Directory Service" -MaxEvents 100 | Where-Object {$_.LevelDisplayName -eq "Error"}
Get-WinEvent -LogName "DNS Server" -MaxEvents 50 | Where-Object {$_.LevelDisplayName -eq "Warning"}

PowerShell Diagnostic Scripts

# AD Health Check Script
function Test-ADReplication
{
    param(
        [string]$DomainName = $env:USERDOMAIN
    )
    
    if ($DomainControllers.Count -eq 0)
    {
        Write-Error "No domain controllers found"
        return
    }

# Usage
$healthCheck = Test-ADHealth
$healthCheck | ConvertTo-Json -Depth 3

Authentication Issues

User Login Problems

Common authentication troubleshooting steps:

# Check user account status
function Test-UserAuthentication
{
    param(
        [Parameter(Mandatory = $true)]
        [string]$Username,
        
        [string]$Domain = $env:USERDOMAIN
    )
    
    try
    {
        # Get user information
        $user = Get-ADUser -Identity $Username -Properties PasswordLastSet, PasswordExpired, LockedOut, Enabled, LastLogonDate
        
        $userStatus = @{
            Username = $user.SamAccountName
            Enabled = $user.Enabled
            LockedOut = $user.LockedOut
            PasswordExpired = $user.PasswordExpired
            PasswordLastSet = $user.PasswordLastSet
            LastLogon = $user.LastLogonDate
            Issues = @()
        }
        
        # Check for common issues
        if (-not $user.Enabled)
        {
            $userStatus.Issues += "Account is disabled"
        }
        
        if ($user.LockedOut)
        {
            $userStatus.Issues += "Account is locked out"
        }
        
        if ($user.PasswordExpired)
        {
            $userStatus.Issues += "Password has expired"
        }
        
        # Check password age
        if ($user.PasswordLastSet)
        {
            $passwordAge = (Get-Date) - $user.PasswordLastSet
            if ($passwordAge.Days -gt 90)
            {
                $userStatus.Issues += "Password is $($passwordAge.Days) days old"
            }
        }
        
        # Check recent login
        if ($user.LastLogonDate)
        {
            $lastLoginAge = (Get-Date) - $user.LastLogonDate
            if ($lastLoginAge.Days -gt 30)
            {
                $userStatus.Issues += "Last login was $($lastLoginAge.Days) days ago"
            }
        }
        
        return $userStatus
    }
    catch
    {
        Write-Error "Failed to retrieve user information: $($_.Exception.Message)"
        return $null
    }
}

# Check authentication events
function Get-AuthenticationEvents
{
    param(
        [string]$Username,
        [int]$Hours = 24
    )
    
    $startTime = (Get-Date).AddHours(-$Hours)
    
    # Common authentication event IDs
    $eventIDs = @(
        4624,  # Successful logon
        4625,  # Failed logon
        4634,  # Successful logoff
        4647,  # User initiated logoff
        4740,  # Account locked out
        4767,  # Account unlocked
        4771,  # Kerberos pre-authentication failed
        4776   # Domain controller attempted to validate credentials
    )
    
    $events = Get-WinEvent -FilterHashtable @{
        LogName = 'Security'
        ID = $eventIDs
        StartTime = $startTime
    } | Where-Object {
        $_.Message -like "*$Username*"
    } | Select-Object TimeCreated, Id, LevelDisplayName, Message
    
    return $events
}

Kerberos Issues

Diagnose Kerberos authentication problems:

# Kerberos ticket diagnostics
function Test-KerberosTickets
{
    param(
        [string]$Username = $env:USERNAME
    )
    
    # List current tickets
    $tickets = klist
    
    # Parse ticket information
    $ticketInfo = @{
        CurrentUser = $Username
        Tickets = @()
        Issues = @()
    }
    
    if ($tickets -match "No tickets")
    {
        $ticketInfo.Issues += "No Kerberos tickets found"
    }
    
    # Check for expired tickets
    if ($tickets -match "expired|invalid")
    {
        $ticketInfo.Issues += "Expired or invalid tickets detected"
    }
    
    # Purge and renew tickets if issues found
    if ($ticketInfo.Issues.Count -gt 0)
    {
        Write-Output "Attempting to resolve Kerberos issues..."
        klist purge
        
        # Force ticket renewal
        try
        {
            $null = nltest /dsgetdc:$env:USERDOMAIN
            $ticketInfo.Resolution = "Tickets purged and renewed"
        }
        catch
        {
            $ticketInfo.Resolution = "Failed to renew tickets: $($_.Exception.Message)"
        }
    }
    
    return $ticketInfo
}

# SPN (Service Principal Name) diagnostics
function Test-ServicePrincipalNames
{
    param(
        [string]$DomainName = $env:USERDOMAIN
    )
    
    try
    {
        $serviceAccounts = Get-ADUser -Filter "ServicePrincipalName -like '*'" -Properties ServicePrincipalNames
        
        $duplicateSpns = @()
        $allSpns = @()
        
        # Collect all SPNs
        foreach ($account in $serviceAccounts)
        {
            $allSpns += $account.ServicePrincipalNames
        }
        
        foreach ($spn in $spns.ServicePrincipalNames)
        {
            $duplicates = $allSpns | Where-Object { $_ -eq $spn }
            if ($duplicates.Count -gt 1)
            {
                $duplicateSpns += [PSCustomObject]@{
                    SPN = $spn
                    Count = $duplicates.Count
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed to check SPNs: $($_.Exception.Message)"
    }
}

Replication Issues

Replication Monitoring

Monitor and troubleshoot AD replication:

# Comprehensive replication check
function Test-ADReplication
{
    param(
        [string[]]$DomainControllers = @()
    )
    
    if ($DomainControllers.Count -eq 0)
    {
        $DomainControllers = (Get-ADDomainController -Filter *).Name
    }
    
    $replicationReport = @{
        Timestamp = Get-Date
        DomainControllers = @{}
        OverallStatus = "Unknown"
        Issues = @()
    }
    
    foreach ($dc in $DomainControllers)
    {
        Write-Output "Checking replication on $($dc.HostName)"
        
        $dcIssues = 0
        
        # Check inbound replication
        try
        {
            $inboundRepl = Get-ADReplicationPartnerMetadata -Target $dc.HostName -PartnerType Inbound
            
            foreach ($repl in $inboundRepl)
            {
                if ($repl.'Last Success Time' -eq "0" -or $repl.'Consecutive Failures' -gt 0)
                {
                    Write-Warning "Inbound replication issue on $($dc.HostName) from $($repl.Partner): Last Success: $($repl.'Last Success Time'), Failures: $($repl.'Consecutive Failures')"
                    $dcIssues++
                }
            }
            
            foreach ($repl in $outboundRepl)
            {
                if ($repl.'Last Success Time' -eq "0" -or $repl.'Consecutive Failures' -gt 0)
                {
                    Write-Warning "Outbound replication issue on $($dc.HostName) to $($repl.Partner): Last Success: $($repl.'Last Success Time'), Failures: $($repl.'Consecutive Failures')"
                    $dcIssues++
                }
            }
        }
        catch
        {
            Write-Error "Failed to check replication on $($dc.HostName): $($_.Exception.Message)"
            $dcIssues++
        }    # Determine overall status
    $totalIssues = ($replicationReport.DomainControllers.Values | ForEach-Object { $_.Issues.Count } | Measure-Object -Sum).Sum
    
    if ($totalIssues -eq 0)
    {
        $replicationReport.OverallStatus = "Healthy"
    }
    elseif ($totalIssues -lt 5)
    {
        $replicationReport.OverallStatus = "Warning"
    }
    else
    {
        $replicationReport.OverallStatus = "Critical"
    }
    
    return $replicationReport
}

# Force replication between DCs
function Invoke-ADReplicationSync
{
    param(
        [Parameter(Mandatory = $true)]
        [string]$SourceDC,
        
        [Parameter(Mandatory = $true)]
        [string]$DestinationDC,
        
        [string]$NamingContext = (Get-ADDomain).DistinguishedName
    )
    
    try
    {
        Write-Output "Forcing replication from $SourceDC to $DestinationDC..."
        
        # Force immediate replication
        $result = repadmin /syncall $DestinationDC $NamingContext /AdeP
        
        if ($result -match "error|fail")
        {
            throw "Replication sync failed: $result"
        }
        
        Write-Output "Replication sync completed successfully"
        return $true
    }
    catch
    {
        Write-Error "Failed to sync replication: $($_.Exception.Message)"
        return $false
    }
}

SYSVOL and FRS Issues

Troubleshoot SYSVOL replication problems:

# SYSVOL health check
function Test-SysvolReplication
{
    param(
        [string[]]$DomainControllers = @()
    )
    
    if ($DomainControllers.Count -eq 0)
    {
        $DomainControllers = (Get-ADDomainController -Filter *).Name
    }
    
    $sysvolReport = @{
        Timestamp = Get-Date
        ReplicationMethod = "Unknown"
        DomainControllers = @{}
        Issues = @()
    }
    
    # Determine replication method (FRS or DFSR)
    try
    {
        $dfsrCheck = Get-WmiObject -Namespace "root\MicrosoftDfs" -Class "DfsrReplicatedFolderInfo" -ErrorAction Stop
        $sysvolReport.ReplicationMethod = "DFSR"
    }
    catch
    {
        $sysvolReport.ReplicationMethod = "FRS"
    }
    
    foreach ($dc in $DomainControllers)
    {
        $dcSysvolStatus = @{
            Name = $dc
            SysvolShare = $false
            NetlogonShare = $false
            ReplicationStatus = "Unknown"
            Issues = @()
        }
        
        try
        {
            # Test SYSVOL share
            $sysvolPath = "\\$dc\SYSVOL"
            if (Test-Path $sysvolPath)
            {
                $dcSysvolStatus.SysvolShare = $true
            }
            else
            {
                $dcSysvolStatus.Issues += "SYSVOL share not accessible"
            }
            
            # Test NETLOGON share
            $netlogonPath = "\\$dc\NETLOGON"
            if (Test-Path $netlogonPath)
            {
                $dcSysvolStatus.NetlogonShare = $true
            }
            else
            {
                $dcSysvolStatus.Issues += "NETLOGON share not accessible"
            }
            
            # Check replication status based on method
            if ($sysvolReport.ReplicationMethod -eq "DFSR")
            {
                $dfsrStatus = dfsrdiag replicationstate /member:$dc
                if ($dfsrStatus -match "error|fail")
                {
                    $dcSysvolStatus.Issues += "DFSR replication issues detected"
                }
            }
            else
            {
                $frsStatus = ntfrsutl ds $dc
                if ($frsStatus -match "error|fail")
                {
                    $dcSysvolStatus.Issues += "FRS replication issues detected"
                }
            }
            
            $sysvolReport.DomainControllers[$dc] = $dcSysvolStatus
        }
        catch
        {
            $dcSysvolStatus.Issues += "Failed to check SYSVOL status: $($_.Exception.Message)"
            $sysvolReport.DomainControllers[$dc] = $dcSysvolStatus
        }
    }
    
    return $sysvolReport
}

DNS Issues

DNS Troubleshooting

Diagnose DNS problems affecting AD:

# Comprehensive DNS check for AD
function Test-ADDnsConfiguration
{
    param(
        [string]$Domain = $env:USERDOMAIN,
        [string[]]$DomainControllers = @()
    )
    
    if ($DomainControllers.Count -eq 0)
    {
        $DomainControllers = (Get-ADDomainController -Filter *).Name
    }
    
    $dnsReport = @{
        Domain = $Domain
        Timestamp = Get-Date
        SRVRecords = @{}
        ARecords = @{}
        Issues = @()
    }
    
    # Critical SRV records to check
    $srvRecords = @(
        "_ldap._tcp.$Domain",
        "_ldap._tcp.dc._msdcs.$Domain",
        "_kerberos._tcp.$Domain",
        "_kpasswd._tcp.$Domain",
        "_gc._tcp.$Domain"
    )
    
    foreach ($srv in $srvRecords)
    {
        try
        {
            $srvResult = Resolve-DnsName -Name $srv -Type SRV -ErrorAction Stop
            $dnsReport.SRVRecords[$srv] = @{
                Status = "Success"
                Records = $srvResult.Count
                Details = $srvResult
            }
        }
        catch
        {
            $dnsReport.SRVRecords[$srv] = @{
                Status = "Failed"
                Error = $_.Exception.Message
            }
            $dnsReport.Issues += "Failed to resolve SRV record: $srv"
        }
    }
    
    # Check A records for domain controllers
    foreach ($dc in $DomainControllers)
    {
        try
        {
            $aResult = Resolve-DnsName -Name $dc -Type A -ErrorAction Stop
            $dnsReport.ARecords[$dc] = @{
                Status = "Success"
                IPAddress = $aResult.IPAddress
            }
        }
        catch
        {
            $dnsReport.ARecords[$dc] = @{
                Status = "Failed"
                Error = $_.Exception.Message
            }
            $dnsReport.Issues += "Failed to resolve A record for DC: $dc"
        }
    }
    
    return $dnsReport
}

# DNS scavenging check
function Test-DnsScavenging
{
    param(
        [string[]]$DnsServers = @()
    )
    
    if ($DnsServers.Count -eq 0)
    {
        $DnsServers = (Get-ADDomainController -Filter *).Name
    }
    
    $scavengingReport = @{
        Timestamp = Get-Date
        Servers = @{}
    }
    
    foreach ($server in $DnsServers)
    {
        try
        {
            $scavengingSettings = Get-DnsServerScavenging -ComputerName $server
            
            $scavengingReport.Servers[$server] = @{
                ScavengingState = $scavengingSettings.ScavengingState
                ScavengingInterval = $scavengingSettings.ScavengingInterval
                LastScavengeTime = $scavengingSettings.LastScavengeTime
                Recommendations = @()
            }
            
            if (-not $scavengingSettings.ScavengingState)
            {
                $scavengingReport.Servers[$server].Recommendations += "Enable DNS scavenging"
            }
            
            if ($scavengingSettings.ScavengingInterval.TotalDays -gt 7)
            {
                $scavengingReport.Servers[$server].Recommendations += "Consider reducing scavenging interval"
            }
        }
        catch
        {
            $scavengingReport.Servers[$server] = @{
                Error = $_.Exception.Message
            }
        }
    }
    
    return $scavengingReport
}

Performance Issues

Performance Monitoring

Monitor AD performance metrics:

# AD performance counters
function Get-ADPerformanceMetrics
{
    param(
        [string]$DomainController = $env:COMPUTERNAME,
        [int]$SampleInterval = 5,
        [int]$SampleCount = 12
    )
    
    $performanceCounters = @(
        "\NTDS\DRA Inbound Bytes Total/sec",
        "\NTDS\DRA Outbound Bytes Total/sec",
        "\NTDS\DS Directory Reads/sec",
        "\NTDS\DS Directory Writes/sec",
        "\NTDS\LDAP Client Sessions",
        "\NTDS\LDAP Searches/sec",
        "\NTDS\LDAP Successful Binds/sec",
        "\NTDS\Kerberos Authentications/sec",
        "\NTDS\NTLM Authentications/sec"
    )
    
    try
    {
        $samples = Get-Counter -ComputerName $DomainController -Counter $performanceCounters -SampleInterval $SampleInterval -MaxSamples $SampleCount
        
        $performanceReport = @{
            DomainController = $DomainController
            SamplePeriod = "$($SampleInterval * $SampleCount) seconds"
            Metrics = @{}
            Alerts = @()
        }
        
        # Calculate averages and identify issues
        foreach ($counter in $performanceCounters)
        {
            $counterSamples = $samples.CounterSamples | Where-Object {$_.Path -like "*$($counter.Split('\')[-1])*"}
            $average = ($counterSamples | Measure-Object -Property CookedValue -Average).Average
            
            $performanceReport.Metrics[$counter] = @{
                Average = [Math]::Round($average, 2)
                Minimum = ($counterSamples | Measure-Object -Property CookedValue -Minimum).Minimum
                Maximum = ($counterSamples | Measure-Object -Property CookedValue -Maximum).Maximum
            }
            
            # Performance thresholds
            switch -Wildcard ($counter) {
                "*LDAP Searches/sec*" {
                    if ($average -gt 1000)
                    {
                        $performanceReport.Alerts += "High LDAP search rate: $([Math]::Round($average, 2))/sec"
                    }
                }
                "*DS Directory Reads/sec*" {
                    if ($average -gt 500)
                    {
                        $performanceReport.Alerts += "High directory read rate: $([Math]::Round($average, 2))/sec"
                    }
                }
                "*LDAP Client Sessions*" {
                    if ($average -gt 1000)
                    {
                        $performanceReport.Alerts += "High LDAP client sessions: $([Math]::Round($average, 2))"
                    }
                }
            }
        }
        
        return $performanceReport
    }
    catch
    {
        Write-Error "Failed to collect performance metrics: $($_.Exception.Message)"
        return $null
    }
}

# Database performance check
function Test-ADDatabasePerformance
{
    param(
        [string]$DomainController = $env:COMPUTERNAME
    )
    
    $databaseReport = @{
        DomainController = $DomainController
        Timestamp = Get-Date
        DatabaseInfo = @{}
        Issues = @()
    }
    
    try
    {
        # Get database file information
        $ntdsutil = "ntdsutil `"activate instance ntds`" files info quit quit"
        $dbInfo = Invoke-Expression $ntdsutil
        
        # Parse database information
        if ($dbInfo -match "Database file: (.+)")
        {
            $dbPath = $matches[1].Trim()
            $dbFile = Get-Item $dbPath -ErrorAction Stop
            
            $databaseReport.DatabaseInfo = @{
                Path = $dbPath
                SizeMB = [Math]::Round($dbFile.Length / 1MB, 2)
                LastModified = $dbFile.LastWriteTime
            }
            
            # Check database size
            if ($dbFile.Length -gt 10GB)
            {
                $databaseReport.Issues += "Large database size: $([Math]::Round($dbFile.Length / 1GB, 2)) GB"
            }
            
            # Check available disk space
            $drive = $dbPath.Substring(0, 2)
            $disk = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.DeviceID -eq $drive}
            $freeSpaceGB = [Math]::Round($disk.FreeSpace / 1GB, 2)
            
            if ($freeSpaceGB -lt 2)
            {
                $databaseReport.Issues += "Low disk space: $freeSpaceGB GB available"
            }
        }
        
        return $databaseReport
    }
    catch
    {
        $databaseReport.Issues += "Failed to check database: $($_.Exception.Message)"
        return $databaseReport
    }
}

Group Policy Issues

Group Policy Troubleshooting

Diagnose GP application problems:

# Group Policy diagnostics
function Test-GroupPolicyApplication
{
    param(
        [string]$ComputerName = $env:COMPUTERNAME,
        [string]$Username = $env:USERNAME
    )
    
    $gpReport = @{
        ComputerName = $ComputerName
        Username = $Username
        Timestamp = Get-Date
        ComputerPolicies = @{}
        UserPolicies = @{}
        Issues = @()
    }
    
    try
    {
        # Run gpresult for detailed information
        $gpResult = gpresult /r /scope:both
        
        # Check last GP refresh times
        $computerRefresh = Get-WinEvent -FilterHashtable @{LogName='System'; ID=1502} -MaxEvents 1 -ErrorAction SilentlyContinue
        if ($computerRefresh)
        {
            $gpReport.ComputerPolicies.LastRefresh = $computerRefresh.TimeCreated
        }
        
        $userRefresh = Get-WinEvent -FilterHashtable @{LogName='Application'; ID=1502} -MaxEvents 1 -ErrorAction SilentlyContinue
        if ($userRefresh)
        {
            $gpReport.UserPolicies.LastRefresh = $userRefresh.TimeCreated
        }
        
        # Check for GP errors
        $gpErrors = Get-WinEvent -FilterHashtable @{LogName='System'; ID=1085,1097} -MaxEvents 10 -ErrorAction SilentlyContinue
        if ($gpErrors)
        {
            $gpReport.Issues += "Group Policy errors found in event log"
        }
        
        # Test network connectivity to domain controller
        $dc = nltest /dsgetdc:$env:USERDOMAIN
        if ($dc -match "error|fail")
        {
            $gpReport.Issues += "Cannot contact domain controller for GP processing"
        }
        
        return $gpReport
    }
    catch
    {
        $gpReport.Issues += "Failed to analyze Group Policy: $($_.Exception.Message)"
        return $gpReport
    }
}

# Force Group Policy refresh
function Invoke-GroupPolicyRefresh
{
    param(
        [switch]$Computer,
        [switch]$User,
        [switch]$Force
    )
    
    try
    {
        $refreshParams = @()
        
        if ($Computer)
        {
            $refreshParams += "/target:computer"
        }
        
        if ($User)
        {
            $refreshParams += "/target:user"
        }
        
        if ($Force)
        {
            $refreshParams += "/force"
        }
        
        $refreshCommand = "gpupdate " + ($refreshParams -join " ")
        
        Write-Output "Executing: $refreshCommand"
        $result = Invoke-Expression $refreshCommand
        
        Write-Output "Group Policy refresh completed"
        return $result
    }
    catch
    {
        Write-Error "Failed to refresh Group Policy: $($_.Exception.Message)"
        return $false
    }
}

Common Troubleshooting Scenarios

Domain Join Issues

Troubleshoot computer domain join problems:

# Domain join diagnostics
function Test-DomainJoinRequirements
{
    param(
        [Parameter(Mandatory = $true)]
        [string]$DomainName,
        
        [Parameter(Mandatory = $true)]
        [string]$ComputerName
    )
    
    $joinReport = @{
        DomainName = $DomainName
        ComputerName = $ComputerName
        Timestamp = Get-Date
        Prerequisites = @{}
        Issues = @()
    }
    
    # Check DNS resolution
    try
    {
        $domainDC = Resolve-DnsName -Name $DomainName -Type A -ErrorAction Stop
        $joinReport.Prerequisites.DNSResolution = "Pass"
    }
    catch
    {
        $joinReport.Prerequisites.DNSResolution = "Fail"
        $joinReport.Issues += "Cannot resolve domain name: $DomainName"
    }
    
    # Check domain controller connectivity
    try
    {
        $dcInfo = nltest /dsgetdc:$DomainName
        if ($dcInfo -match "error|fail")
        {
            throw "Domain controller lookup failed"
        }
        $joinReport.Prerequisites.DCConnectivity = "Pass"
    }
    catch
    {
        $joinReport.Prerequisites.DCConnectivity = "Fail"
        $joinReport.Issues += "Cannot contact domain controller for $DomainName"
    }
    
    # Check time synchronization
    try
    {
        $timeDiff = w32tm /stripchart /computer:$DomainName /samples:1 /dataonly
        if ($timeDiff -match "error")
        {
            throw "Time sync check failed"
        }
        $joinReport.Prerequisites.TimeSync = "Pass"
    }
    catch
    {
        $joinReport.Prerequisites.TimeSync = "Warning"
        $joinReport.Issues += "Time synchronization may be an issue"
    }
    
    # Check network connectivity
    try
    {
        $pingResult = Test-Connection -ComputerName $DomainName -Count 2 -ErrorAction Stop
        $joinReport.Prerequisites.NetworkConnectivity = "Pass"
    }
    catch
    {
        $joinReport.Prerequisites.NetworkConnectivity = "Fail"
        $joinReport.Issues += "Network connectivity issues to domain"
    }
    
    return $joinReport
}

Trust Relationship Issues

Diagnose trust relationship problems:

# Trust relationship diagnostics
function Test-ComputerTrustRelationship
{
    param(
        [string]$ComputerName = $env:COMPUTERNAME,
        [string]$Domain = $env:USERDOMAIN
    )
    
    $trustReport = @{
        ComputerName = $ComputerName
        Domain = $Domain
        Timestamp = Get-Date
        TrustStatus = "Unknown"
        Issues = @()
        Resolution = @()
    }
    
    try
    {
        # Test secure channel
        $trustTest = nltest /sc_query:$Domain
        
        if ($trustTest -match "success")
        {
            $trustReport.TrustStatus = "Healthy"
        }
        elseif ($trustTest -match "error|fail")
        {
            $trustReport.TrustStatus = "Broken"
            $trustReport.Issues += "Secure channel test failed"
            $trustReport.Resolution += "Reset computer account password"
        }
        
        # Additional checks if trust is broken
        if ($trustReport.TrustStatus -eq "Broken")
        {
            # Try to reset secure channel
            Write-Output "Attempting to reset secure channel..."
            $resetResult = nltest /sc_reset:$Domain
            
            if ($resetResult -match "success")
            {
                $trustReport.Resolution += "Secure channel reset successful"
                $trustReport.TrustStatus = "Repaired"
            }
            else
            {
                $trustReport.Resolution += "Secure channel reset failed - manual intervention required"
            }
        }
        
        return $trustReport
    }
    catch
    {
        $trustReport.Issues += "Failed to test trust relationship: $($_.Exception.Message)"
        return $trustReport
    }
}

Event Log Analysis

Critical Event Monitoring

Monitor and analyze AD-related events:

# AD event analysis
function Get-ADCriticalEvents
{
    param(
        [int]$Hours = 24,
        [string[]]$ComputerName = @($env:COMPUTERNAME)
    )
    
    $startTime = (Get-Date).AddHours(-$Hours)
    
    # Critical AD event IDs
    $criticalEvents = @{
        # Authentication events
        4771 = "Kerberos pre-authentication failed"
        4776 = "Domain controller attempted to validate credentials"
        4740 = "Account locked out"
        
        # Replication events
        1311 = "Knowledge Consistency Checker error"
        1388 = "Replication error"
        
        # DNS events
        4013 = "DNS server unable to load zone"
        4015 = "DNS server unable to start"
        
        # Directory Service events
        1202 = "Directory service could not be initialized"
        1173 = "Internal error in Active Directory"
    }
    
    $eventReport = @{
        TimeRange = "$Hours hours"
        StartTime = $startTime
        Computers = @{}
        Summary = @{
            TotalEvents = 0
            CriticalCount = 0
            WarningCount = 0
        }
    }
    
    foreach ($computer in $ComputerName)
    {
        $computerEvents = @{
            ComputerName = $computer
            Events = @()
            Summary = @{
                Critical = 0
                Warning = 0
                Information = 0
            }
        }
        
        try
        {
            foreach ($eventId in $criticalEvents.Keys)
            {
                $events = Get-WinEvent -ComputerName $computer -FilterHashtable @{
                    LogName = 'Security', 'System', 'Directory Service', 'DNS Server'
                    ID = $eventId
                    StartTime = $startTime
                } -ErrorAction SilentlyContinue
                
                foreach ($event in $events)
                {
                    $eventInfo = @{
                        EventId = $event.Id
                        Level = $event.LevelDisplayName
                        TimeCreated = $event.TimeCreated
                        Description = $criticalEvents[$event.Id]
                        Message = $event.Message.Substring(0, [Math]::Min(200, $event.Message.Length))
                    }
                    
                    $computerEvents.Events += $eventInfo
                    $computerEvents.Summary[$event.LevelDisplayName]++
                    $eventReport.Summary.TotalEvents++
                    
                    if ($event.LevelDisplayName -eq "Critical")
                    {
                        $eventReport.Summary.CriticalCount++
                    }
                    elseif ($event.LevelDisplayName -eq "Warning")
                    {
                        $eventReport.Summary.WarningCount++
                    }
                }
            }
            
            $eventReport.Computers[$computer] = $computerEvents
        }
        catch
        {
            Write-Warning "Failed to retrieve events from $computer`: $($_.Exception.Message)"
        }
    }
    
    return $eventReport
}

Recovery Procedures

Authoritative Restore

Perform authoritative restore of AD objects:

# Authoritative restore guidance
function New-AuthoritativeRestorePlan
{
    param(
        [Parameter(Mandatory = $true)]
        [string]$ObjectDN,
        
        [string]$BackupDate,
        [switch]$DryRun
    )
    
    $restorePlan = @{
        ObjectDN = $ObjectDN
        BackupDate = $BackupDate
        DryRun = $DryRun
        Steps = @()
        Warnings = @()
        Prerequisites = @()
    }
    
    # Add prerequisites
    $restorePlan.Prerequisites += "Boot domain controller into Directory Services Restore Mode"
    $restorePlan.Prerequisites += "Restore system state from backup dated $BackupDate"
    $restorePlan.Prerequisites += "Ensure network connectivity to other domain controllers"
    
    # Add restoration steps
    $restorePlan.Steps += "Start in Directory Services Restore Mode"
    $restorePlan.Steps += "Restore system state: wbadmin start systemstaterecovery -version:$BackupDate"
    $restorePlan.Steps += "Mark object as authoritative: ntdsutil `"authoritative restore`" `"restore object $ObjectDN`""
    $restorePlan.Steps += "Restart in normal mode"
    $restorePlan.Steps += "Force replication to other DCs"
    
    # Add warnings
    $restorePlan.Warnings += "Authoritative restore will overwrite newer changes"
    $restorePlan.Warnings += "Test in lab environment first"
    $restorePlan.Warnings += "Backup current state before proceeding"
    
    if ($DryRun)
    {
        Write-Output "DRY RUN - Authoritative Restore Plan:"
        $restorePlan | ConvertTo-Json -Depth 3
    }
    
    return $restorePlan
}

This troubleshooting guide provides systematic approaches to diagnosing and resolving Active Directory issues. Regular monitoring and proactive maintenance help prevent many common problems.