FSMO Analyzer Tool
<# .SYNOPSIS FSMO Analyzer Tool .DESCRIPTION This script analyzes FSMO roles in an Active Directory environment, providing detailed information about role holders, health status, and potential issues. .NOTES File Name : FSMOAnalyzer.ps1 Author : [Your Name] Prerequisite : PowerShell V5.1 or later, Active Directory module, and appropriate AD permissions Version : 1.0 Date : [Current Date] .EXAMPLE .\FSMOAnalyzer.ps1 #> # Import required modules Import-Module ActiveDirectory # Global variables $global:reportPath = "$env:USERPROFILE\Desktop\FSMO_Analysis_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').html" <# .SYNOPSIS Displays the main menu of the tool. #> function Show-Menu { Clear-Host Write-Host "=== FSMO Analyzer Tool ===" -ForegroundColor Cyan Write-Host "1. Identify FSMO Role Holders" Write-Host "2. Check FSMO Role Health" Write-Host "3. Analyze FSMO Role Transfer History" Write-Host "4. Verify FSMO Role Connectivity" Write-Host "5. Check for Orphaned FSMO Roles" Write-Host "6. Analyze FSMO Role Performance" Write-Host "7. Generate Comprehensive HTML Report" Write-Host "8. Exit" } <# .SYNOPSIS Identifies current FSMO role holders. .OUTPUTS PSObject containing FSMO role holder information. #> function Identify-FSMORoleHolders { Write-Host "`nIdentifying FSMO Role Holders..." -ForegroundColor Yellow $forest = Get-ADForest $domain = Get-ADDomain $fsmoRoles = [PSCustomObject]@{ SchemaMaster = $forest.SchemaMaster DomainNamingMaster = $forest.DomainNamingMaster PDCEmulator = $domain.PDCEmulator RIDMaster = $domain.RIDMaster InfrastructureMaster = $domain.InfrastructureMaster } $fsmoRoles | Format-List return $fsmoRoles } <# .SYNOPSIS Checks the health of FSMO roles. .OUTPUTS Array of PSObjects containing FSMO role health information. #> function Check-FSMORoleHealth { Write-Host "`nChecking FSMO Role Health..." -ForegroundColor Yellow $roles = Identify-FSMORoleHolders $healthResults = @() foreach ($role in $roles.PSObject.Properties) { $dcdiag = Invoke-Command -ComputerName $role.Value -ScriptBlock { dcdiag /test:KnowsOfRoleHolders /test:RegisterInDNS } -ErrorAction SilentlyContinue $healthResults += [PSCustomObject]@{ Role = $role.Name Holder = $role.Value KnowsOfRoleHolders = if ($dcdiag -match "passed test KnowsOfRoleHolders") { "Passed" } else { "Failed" } RegisteredInDNS = if ($dcdiag -match "passed test RegisterInDNS") { "Passed" } else { "Failed" } } } $healthResults | Format-Table -AutoSize return $healthResults } <# .SYNOPSIS Analyzes FSMO role transfer history. .OUTPUTS Array of PSObjects containing FSMO role transfer history. #> function Analyze-FSMORoleTransferHistory { Write-Host "`nAnalyzing FSMO Role Transfer History..." -ForegroundColor Yellow $domain = Get-ADDomain $forest = Get-ADForest $transferHistory = @() $events = Get-WinEvent -ComputerName $domain.PDCEmulator -FilterHashtable @{ LogName = 'Directory Service' ID = 1190, 1647, 2162 } -ErrorAction SilentlyContinue foreach ($event in $events) { $transferHistory += [PSCustomObject]@{ TimeStamp = $event.TimeCreated EventID = $event.Id Message = $event.Message } } $transferHistory | Format-Table -AutoSize return $transferHistory } <# .SYNOPSIS Verifies connectivity to FSMO role holders. .OUTPUTS Array of PSObjects containing FSMO role connectivity information. #> function Verify-FSMORoleConnectivity { Write-Host "`nVerifying FSMO Role Connectivity..." -ForegroundColor Yellow $roles = Identify-FSMORoleHolders $connectivityResults = @() foreach ($role in $roles.PSObject.Properties) { $pingResult = Test-Connection -ComputerName $role.Value -Count 1 -Quiet $portResult = Test-NetConnection -ComputerName $role.Value -Port 389 -WarningAction SilentlyContinue $connectivityResults += [PSCustomObject]@{ Role = $role.Name Holder = $role.Value Pingable = $pingResult LDAPAccessible = $portResult.TcpTestSucceeded } } $connectivityResults | Format-Table -AutoSize return $connectivityResults } <# .SYNOPSIS Checks for orphaned FSMO roles. .OUTPUTS Array of PSObjects containing orphaned FSMO role information. #> function Check-OrphanedFSMORoles { Write-Host "`nChecking for Orphaned FSMO Roles..." -ForegroundColor Yellow $roles = Identify-FSMORoleHolders $orphanedRoles = @() foreach ($role in $roles.PSObject.Properties) { $dcExists = Get-ADDomainController -Identity $role.Value -ErrorAction SilentlyContinue if (-not $dcExists) { $orphanedRoles += [PSCustomObject]@{ Role = $role.Name Holder = $role.Value Status = "Orphaned" } } } if ($orphanedRoles.Count -eq 0) { Write-Host "No orphaned FSMO roles found." -ForegroundColor Green } else { $orphanedRoles | Format-Table -AutoSize } return $orphanedRoles } <# .SYNOPSIS Analyzes FSMO role performance. .OUTPUTS Array of PSObjects containing FSMO role performance information. #> function Analyze-FSMORolePerformance { Write-Host "`nAnalyzing FSMO Role Performance..." -ForegroundColor Yellow $roles = Identify-FSMORoleHolders $performanceResults = @() foreach ($role in $roles.PSObject.Properties) { $cpu = Get-WmiObject Win32_Processor -ComputerName $role.Value | Measure-Object -Property LoadPercentage -Average | Select-Object -ExpandProperty Average $memory = Get-WmiObject Win32_OperatingSystem -ComputerName $role.Value | Select-Object @{Name="MemoryUsage";Expression={"{0:N2}" -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize)}} $disk = Get-WmiObject Win32_LogicalDisk -ComputerName $role.Value -Filter "DeviceID='C:'" | Select-Object @{Name="FreeSpace";Expression={"{0:N2}" -f ($_.FreeSpace/1GB)}} $performanceResults += [PSCustomObject]@{ Role = $role.Name Holder = $role.Value CPUUsage = "$cpu%" MemoryUsage = "$($memory.MemoryUsage)%" FreeDiskSpace = "$($disk.FreeSpace) GB" } } $performanceResults | Format-Table -AutoSize return $performanceResults } <# .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>FSMO Role 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>FSMO Role Analysis Report</h1> <p>Generated on: $(Get-Date)</p> <h2>FSMO Role Holders</h2> $($AllResults.RoleHolders | ConvertTo-Html -Fragment) <h2>FSMO Role Health</h2> $($AllResults.RoleHealth | ConvertTo-Html -Fragment) <h2>FSMO Role Transfer History</h2> $($AllResults.TransferHistory | ConvertTo-Html -Fragment) <h2>FSMO Role Connectivity</h2> $($AllResults.RoleConnectivity | ConvertTo-Html -Fragment) <h2>Orphaned FSMO Roles</h2> $($AllResults.OrphanedRoles | ConvertTo-Html -Fragment) <h2>FSMO Role Performance</h2> $($AllResults.RolePerformance | 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-8)" switch ($choice) { "1" { $allResults.RoleHolders = Identify-FSMORoleHolders } "2" { $allResults.RoleHealth = Check-FSMORoleHealth } "3" { $allResults.TransferHistory = Analyze-FSMORoleTransferHistory } "4" { $allResults.RoleConnectivity = Verify-FSMORoleConnectivity } "5" { $allResults.OrphanedRoles = Check-OrphanedFSMORoles } "6" { $allResults.RolePerformance = Analyze-FSMORolePerformance } "7" { Generate-HTMLReport -AllResults $allResults } "8" { Write-Host "Exiting program..." -ForegroundColor Yellow; break } default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red } } if ($choice -ne "8") { Read-Host "`nPress Enter to continue..." } } while ($choice -ne "8")
This FSMO Analyzer Tool includes:
- A menu-driven interface for easy navigation.
- Functions to analyze various aspects of FSMO roles:
- Identification of current FSMO role holders
- Health check of FSMO roles
- Analysis of FSMO role transfer history
- Verification of connectivity to FSMO role holders
- Check for orphaned FSMO roles
- Performance analysis of FSMO role holders
- Comprehensive error handling for each analysis function.
- A function to generate an HTML report of all collected data.
Key features:
- Detailed identification of all FSMO role holders
- Health check of FSMO roles using dcdiag
- Analysis of recent FSMO role transfers
- Connectivity tests to ensure FSMO role holders are accessible
- Detection of orphaned FSMO roles
- Performance metrics of servers holding FSMO roles
- HTML report generation for easy sharing and viewing of results
This tool is particularly useful for:
- Active Directory administrators
- System administrators managing domain controllers
- IT professionals troubleshooting AD issues related to FSMO roles
- Security teams auditing AD infrastructure
To use this script effectively:
- Run PowerShell as an administrator
- Ensure you have the necessary permissions to query domain controllers and FSMO role holders
- Have the Active Directory PowerShell module installed
This script provides a comprehensive overview of FSMO roles in an Active Directory environment, making it easier to identify issues, track changes, and ensure the health and performance of these critical roles. It can significantly streamline the process of maintaining and troubleshooting FSMO roles in organizations of any size.

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