NETLOGON Analyzer Tool
<# .SYNOPSIS NETLOGON Analyzer Tool .DESCRIPTION This script analyzes NETLOGON-related issues, log files, and configurations across Domain Controllers in an Active Directory environment. .NOTES File Name : NETLOGONAnalyzer.ps1 Author : [Your Name] Prerequisite : PowerShell V5.1 or later, Active Directory module, and appropriate AD permissions Version : 1.0 Date : [Current Date] .EXAMPLE .\NETLOGONAnalyzer.ps1 #> # Import required modules Import-Module ActiveDirectory # Global variables $global:reportPath = "$env:USERPROFILE\Desktop\NETLOGON_Analysis_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').html" <# .SYNOPSIS Displays the main menu of the tool. #> function Show-Menu { Clear-Host Write-Host "=== NETLOGON Analyzer Tool ===" -ForegroundColor Cyan Write-Host "1. Check NETLOGON Service Status" Write-Host "2. Analyze NETLOGON Log Files" Write-Host "3. Verify NETLOGON Share Accessibility" Write-Host "4. Check NETLOGON Registry Settings" Write-Host "5. Analyze NETLOGON-related Group Policies" Write-Host "6. Check Secure Channel Status" Write-Host "7. Analyze NETLOGON Performance Counters" Write-Host "8. Generate Comprehensive HTML Report" Write-Host "9. Exit" } <# .SYNOPSIS Checks NETLOGON service status on all Domain Controllers. .OUTPUTS Array of PSObjects containing NETLOGON service status for each DC. #> function Check-NETLOGONServiceStatus { Write-Host "`nChecking NETLOGON Service Status..." -ForegroundColor Yellow $dcs = Get-ADDomainController -Filter * $serviceStatus = @() foreach ($dc in $dcs) { $status = Get-Service -ComputerName $dc.HostName -Name "Netlogon" -ErrorAction SilentlyContinue $serviceStatus += [PSCustomObject]@{ DomainController = $dc.HostName Status = if ($status) { $status.Status } else { "Unable to retrieve" } StartType = if ($status) { $status.StartType } else { "Unknown" } } } $serviceStatus | Format-Table -AutoSize return $serviceStatus } <# .SYNOPSIS Analyzes NETLOGON log files on all Domain Controllers. .OUTPUTS Array of PSObjects containing NETLOGON log analysis for each DC. #> function Analyze-NETLOGONLogFiles { Write-Host "`nAnalyzing NETLOGON Log Files..." -ForegroundColor Yellow $dcs = Get-ADDomainController -Filter * $logAnalysis = @() foreach ($dc in $dcs) { $logPath = "\\$($dc.HostName)\c$\Windows\debug\netlogon.log" if (Test-Path $logPath) { $logContent = Get-Content $logPath -Tail 100 $errorCount = ($logContent | Select-String -Pattern "ERROR" -CaseSensitive).Count $warningCount = ($logContent | Select-String -Pattern "WARNING" -CaseSensitive).Count $recentErrors = $logContent | Select-String -Pattern "ERROR" -CaseSensitive | Select-Object -Last 5 $logAnalysis += [PSCustomObject]@{ DomainController = $dc.HostName ErrorCount = $errorCount WarningCount = $warningCount RecentErrors = $recentErrors -join "`n" } } else { $logAnalysis += [PSCustomObject]@{ DomainController = $dc.HostName ErrorCount = "N/A" WarningCount = "N/A" RecentErrors = "Unable to access log file" } } } $logAnalysis | Format-Table -AutoSize return $logAnalysis } <# .SYNOPSIS Verifies NETLOGON share accessibility on all Domain Controllers. .OUTPUTS Array of PSObjects containing NETLOGON share accessibility status for each DC. #> function Verify-NETLOGONShareAccessibility { Write-Host "`nVerifying NETLOGON Share Accessibility..." -ForegroundColor Yellow $dcs = Get-ADDomainController -Filter * $shareStatus = @() foreach ($dc in $dcs) { $sharePath = "\\$($dc.HostName)\NETLOGON" $accessible = Test-Path $sharePath -ErrorAction SilentlyContinue $shareStatus += [PSCustomObject]@{ DomainController = $dc.HostName ShareAccessible = $accessible SharePath = $sharePath } } $shareStatus | Format-Table -AutoSize return $shareStatus } <# .SYNOPSIS Checks NETLOGON-related registry settings on all Domain Controllers. .OUTPUTS Array of PSObjects containing NETLOGON registry settings for each DC. #> function Check-NETLOGONRegistrySettings { Write-Host "`nChecking NETLOGON Registry Settings..." -ForegroundColor Yellow $dcs = Get-ADDomainController -Filter * $registrySettings = @() foreach ($dc in $dcs) { $settings = Invoke-Command -ComputerName $dc.HostName -ScriptBlock { $netlogonParams = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" -ErrorAction SilentlyContinue return @{ MaximumLogFileSize = $netlogonParams.MaximumLogFileSize DebugFlag = $netlogonParams.DbFlag ScavengeInterval = $netlogonParams.ScavengeInterval } } -ErrorAction SilentlyContinue $registrySettings += [PSCustomObject]@{ DomainController = $dc.HostName MaxLogFileSize = if ($settings) { $settings.MaximumLogFileSize } else { "Unable to retrieve" } DebugFlag = if ($settings) { $settings.DebugFlag } else { "Unable to retrieve" } ScavengeInterval = if ($settings) { $settings.ScavengeInterval } else { "Unable to retrieve" } } } $registrySettings | Format-Table -AutoSize return $registrySettings } <# .SYNOPSIS Analyzes NETLOGON-related Group Policies. .OUTPUTS Array of PSObjects containing NETLOGON-related Group Policy settings. #> function Analyze-NETLOGONGroupPolicies { Write-Host "`nAnalyzing NETLOGON-related Group Policies..." -ForegroundColor Yellow $gpos = Get-GPO -All | Where-Object { $_.DisplayName -like "*NETLOGON*" -or $_.DisplayName -like "*Secure Channel*" } $gpAnalysis = @() foreach ($gpo in $gpos) { $report = Get-GPOReport -Guid $gpo.Id -ReportType XML $netlogonSettings = ([xml]$report).GPO.Computer.ExtensionData.Extension.Policy | Where-Object { $_.Name -like "*NETLOGON*" -or $_.Name -like "*Secure Channel*" } foreach ($setting in $netlogonSettings) { $gpAnalysis += [PSCustomObject]@{ GPOName = $gpo.DisplayName PolicyName = $setting.Name PolicyState = $setting.State } } } $gpAnalysis | Format-Table -AutoSize return $gpAnalysis } <# .SYNOPSIS Checks Secure Channel status for all Domain Controllers. .OUTPUTS Array of PSObjects containing Secure Channel status for each DC. #> function Check-SecureChannelStatus { Write-Host "`nChecking Secure Channel Status..." -ForegroundColor Yellow $dcs = Get-ADDomainController -Filter * $secureChannelStatus = @() foreach ($dc in $dcs) { $status = Test-ComputerSecureChannel -Server $dc.HostName -ErrorAction SilentlyContinue $secureChannelStatus += [PSCustomObject]@{ DomainController = $dc.HostName SecureChannelStatus = if ($status) { "Healthy" } else { "Unhealthy" } } } $secureChannelStatus | Format-Table -AutoSize return $secureChannelStatus } <# .SYNOPSIS Analyzes NETLOGON-related performance counters on all Domain Controllers. .OUTPUTS Array of PSObjects containing NETLOGON performance counter data for each DC. #> function Analyze-NETLOGONPerformanceCounters { Write-Host "`nAnalyzing NETLOGON Performance Counters..." -ForegroundColor Yellow $dcs = Get-ADDomainController -Filter * $perfCounters = @() foreach ($dc in $dcs) { $counters = Invoke-Command -ComputerName $dc.HostName -ScriptBlock { $netlogonCounters = Get-Counter -Counter @( "\Netlogon(*)\*" ) -ErrorAction SilentlyContinue return $netlogonCounters.CounterSamples | Select-Object Path, CookedValue } -ErrorAction SilentlyContinue if ($counters) { $perfCounters += [PSCustomObject]@{ DomainController = $dc.HostName Semaphore_Acquires = ($counters | Where-Object { $_.Path -like "*Semaphore Acquires*" }).CookedValue Semaphore_Timeouts = ($counters | Where-Object { $_.Path -like "*Semaphore Timeouts*" }).CookedValue Semaphore_Holders = ($counters | Where-Object { $_.Path -like "*Semaphore Holders*" }).CookedValue Semaphore_Waiters = ($counters | Where-Object { $_.Path -like "*Semaphore Waiters*" }).CookedValue } } else { $perfCounters += [PSCustomObject]@{ DomainController = $dc.HostName Semaphore_Acquires = "Unable to retrieve" Semaphore_Timeouts = "Unable to retrieve" Semaphore_Holders = "Unable to retrieve" Semaphore_Waiters = "Unable to retrieve" } } } $perfCounters | Format-Table -AutoSize return $perfCounters } <# .SYNOPSIS Generates a comprehensive HTML report of all analyses. .PARAMETER AllResults Hashtable containing all analysis results. .OUTPUTS Saves an HTML report to the desktop. #> function Generate-HTMLReport { param([hashtable]$AllResults) 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>NETLOGON Analysis 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, h3 { 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>NETLOGON Analysis Report</h1> <p>Generated on: $(Get-Date)</p> <h2>NETLOGON Service Status</h2> $($AllResults.ServiceStatus | ConvertTo-Html -Fragment) <h2>NETLOGON Log File Analysis</h2> $($AllResults.LogAnalysis | ConvertTo-Html -Fragment) <h2>NETLOGON Share Accessibility</h2> $($AllResults.ShareStatus | ConvertTo-Html -Fragment) <h2>NETLOGON Registry Settings</h2> $($AllResults.RegistrySettings | ConvertTo-Html -Fragment) <h2>NETLOGON-related Group Policies</h2> $($AllResults.GPAnalysis | ConvertTo-Html -Fragment) <h2>Secure Channel Status</h2> $($AllResults.SecureChannelStatus | ConvertTo-Html -Fragment) <h2>NETLOGON Performance Counters</h2> $($AllResults.PerfCounters | 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 $allResults = @{} do { Show-Menu $choice = Read-Host "`nEnter your choice (1-9)" switch ($choice) { "1" { $allResults.ServiceStatus = Check-NETLOGONServiceStatus } "2" { $allResults.LogAnalysis = Analyze-NETLOGONLogFiles } "3" { $allResults.ShareStatus = Verify-NETLOGONShareAccessibility } "4" { $allResults.RegistrySettings = Check-NETLOGONRegistrySettings } "5" { $allResults.GPAnalysis = Analyze-NETLOGONGroupPolicies } "6" { $allResults.SecureChannelStatus = Check-SecureChannelStatus } "7" { $allResults.PerfCounters = Analyze-NETLOGONPerformanceCounters } "8" { Generate-HTMLReport -AllResults $allResults } "9" { Write-Host "Exiting program..." -ForegroundColor Yellow; break } default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red } } if ($choice -ne "9") { Read-Host "`nPress Enter to continue..." } } while ($choice -ne "9")
This NETLOGON Analyzer Tool includes:
- A menu-driven interface for easy navigation.
- Functions to analyze various aspects of NETLOGON:
- NETLOGON Service Status check
- NETLOGON Log File analysis
- NETLOGON Share accessibility verification
- NETLOGON Registry Settings check
- NETLOGON-related Group Policy analysis
- Secure Channel status check
- NETLOGON Performance Counter analysis
- Comprehensive error handling for each analysis function.
- A function to generate an HTML report of all collected data.
Key features:
- Detailed analysis of NETLOGON service status across all Domain Controllers
- Examination of NETLOGON log files for errors and warnings
- Verification of NETLOGON share accessibility
- Analysis of NETLOGON-related registry settings
- Review of Group Policies affecting NETLOGON
- Checking Secure Channel status for each DC
- Analysis of NETLOGON performance counters
- HTML report generation for easy sharing and viewing of results
This tool is particularly useful for:
- Active Directory administrators
- System administrators troubleshooting NETLOGON issues
- IT professionals performing AD health checks
- Security teams auditing AD configurations
To use this script effectively:
- Run PowerShell as an administrator
- Ensure you have the necessary permissions to query Domain Controllers and access NETLOGON-related information
- Have the Active Directory PowerShell module installed
This script provides a comprehensive overview of NETLOGON-related configurations and potential issues across an Active Directory environment. It can significantly streamline the process of troubleshooting NETLOGON problems and maintaining a healthy AD infrastructure.

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