Daily Active Directory Monitoring Made Easy with PowerShell
If you’re a Domain Admin responsible for maintaining the health of your Active Directory environment, running dcdiag and repadmin commands daily can be time-consuming. To simplify this routine task, I’ve created a PowerShell script that automates these checks and generates a clear, HTML-based report. This makes daily AD monitoring faster, easier, and far more efficient — a real time-saver for any IT admin
Pre-requisites
- GMSA Account to run the Scheduled Tasks
- Domain Admin rights for the GMSA Account
- Valid Email address and SMTP Address
Usage
Copy the Powershell code
Edit the email settings in the highlighted part
Run the Powershell
######################################################################################################## # Author: Karanth # Modified : 19/6/2025 # Usage : To gather Domain Controllers and their Status ######################################################################################################## ###########################Define Variables##################################################### <# .SYNOPSIS Get-ADHealth.ps1 #> # Defining the Variables $allTestedDomainControllers = [System.Collections.Generic.List[Object]]::new() $allDomainControllers = [System.Collections.Generic.List[Object]]::new() $now = Get-Date $date = $now.ToShortDateString() $reportTime = $now $reportFileNameTime = $now.ToString("yyyyMMdd_HHmmss") $reportemailsubject = "Active Directory Health Check for $allDomains" $smtpsettings = @{ To = 'XXYY@xx.com ' From = 'XXYY@xx.com' Subject = "$reportemailsubject - $date" SmtpServer = "XXYY@xx.com" Port = "25" } # Funtion to gather Domain Info Function Get-AllDomains() { Write-Verbose "Running function Get-AllDomains" $allDomains = (Get-ADForest).Domains return $allDomains } # Funtion to gather Domain Controllers name Function Get-AllDomainControllers ($ComputerName) { Write-Verbose "Running function Get-AllDomainControllers" $allDomainControllers = Get-ADDomainController -Filter * -Server $ComputerName | Sort-Object HostName return $allDomainControllers } # Funtion to gather Domain Controllers Uptime Function Get-DomainControllerUptimeDays { param($ComputerName) Write-Verbose "Running function Get-DomainControllerUptimeDays" if (Test-Connection $ComputerName -Count 1 -Quiet) { try { $W32OS = Get-WmiObject Win32_OperatingSystem -ComputerName $ComputerName -ErrorAction Stop if ($W32OS) { $uptimeDays = ($W32OS | Select-Object -ExpandProperty LastBootUpTime) $lastBoot = $W32OS.ConvertToDateTime($uptimeDays) $uptime = (New-TimeSpan -Start $lastBoot -End (Get-Date)).Days } else { $uptime = "Data Error" } } catch { $uptime = 'WMI Failure' } } else { $uptime = 'Fail' } return $uptime } # Funtion to gather NETLOGON and NTDS Services Function Get-DomainControllerServices($ComputerName) { Write-Verbose "Running function DomainControllerServices" $thisDomainControllerServicesTestResult = [PSCustomObject]@{ NTDSService = $null NETLOGONService = $null } if ((Test-Connection $ComputerName -Count 1 -quiet) -eq $True) { if ((Get-Service -ComputerName $ComputerName -Name NTDS -ErrorAction SilentlyContinue).Status -eq 'Running') { $thisDomainControllerServicesTestResult.NTDSService = 'Success' } else { $thisDomainControllerServicesTestResult.NTDSService = 'Fail' } if ((Get-Service -ComputerName $ComputerName -Name netlogon -ErrorAction SilentlyContinue).Status -eq 'Running') { $thisDomainControllerServicesTestResult.NETLOGONService = 'Success' } else { $thisDomainControllerServicesTestResult.NETLOGONService = 'Fail' } } else { $thisDomainControllerServicesTestResult.NTDSService = 'Fail' $thisDomainControllerServicesTestResult.NETLOGONService = 'Fail' } return $thisDomainControllerServicesTestResult } # Funtion to gather DCDIAG results Function Get-DomainControllerDCDiagTestResults($ComputerName) { Write-Verbose "Running function Get-DomainControllerDCDiagTestResults" $DCDiagTestResults = [PSCustomObject]@{ ServerName = $ComputerName Connectivity = $null Advertising = $null FrsEvent = $null DFSREvent = $null SysVolCheck = $null KccEvent = $null KnowsOfRoleHolders = $null NetLogons = $null ObjectsReplicated = $null Replications = $null RidManager = $null Services = $null } if ((Test-Connection $ComputerName -Count 1 -quiet) -eq $True) { $params = @( "/s:$ComputerName", "/test:Connectivity", "/test:Advertising", "/test:FrsEvent", "/test:DFSREvent", "/test:SysVolCheck", "/test:KccEvent", "/test:KnowsOfRoleHolders", "/test:NetLogons", "/test:ObjectsReplicated", "/test:Replications", "/test:RidManager", "/test:Services" ) $DCDiagTest = (Dcdiag.exe @params) -split ('[\r\n]') $TestName = $null $TestStatus = $null $DCDiagTest | ForEach-Object { switch -Regex ($_) { "Starting test:" { $TestName = ($_ -replace ".*Starting test:").Trim() } "passed test|failed test" { $TestStatus = if ($_ -match "passed test") { "Passed" } else { "Failed" } } } if ($TestName -and $TestStatus) { $DCDiagTestResults.$TestName = $TestStatus $TestName = $null $TestStatus = $null } } } else { foreach ($property in $DCDiagTestResults.PSObject.Properties.Name) { if ($property -ne "ServerName") { $DCDiagTestResults.$property = "Failed" } } } return $DCDiagTestResults } # Funtion to gather Free space in C drive Function Get-DomainControllerOSDriveFreeSpaceGB { Param($ComputerName) Write-Verbose "Running function Get-DomainControllerOSDriveFreeSpaceGB" if (Test-Connection $ComputerName -Count 1 -Quiet) { try { $os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName -ErrorAction Stop $osDriveLetter = $os.SystemDrive $osDrive = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $ComputerName ` -Filter "DeviceID='$osDriveLetter'" -ErrorAction Stop $freeSpaceGB = [math]::Round($osDrive.FreeSpace / 1GB, 2) } catch { $freeSpaceGB = 'WMI Failure' } } else { $freeSpaceGB = 'Fail' } return $freeSpaceGB } # Funtion to gather Domain Controllers CPU Usage Function Get-DomainControllerCPUUsage { Param($ComputerName) Write-Verbose "Running function Get-DomainControllerCPUUsage" if (Test-Connection $ComputerName -Count 1 -Quiet) { try { $avgProc = Get-WmiObject -Class win32_processor -ComputerName $ComputerName -ErrorAction Stop | Measure-Object -Property LoadPercentage -Average | Select-Object -ExpandProperty Average $cpuLoad = [math]::Round($avgProc, 2) } catch { $cpuLoad = 'WMI Failure' } } else { $cpuLoad = 'Fail' } return $cpuLoad } # Funtion to gather Memory Usage Function Get-DomainControllerMemoryUsage { Param($ComputerName) Write-Verbose "Running function Get-DomainControllerMemoryUsage" if (Test-Connection $ComputerName -Count 1 -Quiet) { try { $os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName -ErrorAction Stop $total = $os.TotalVisibleMemorySize $free = $os.FreePhysicalMemory $used = $total - $free $memPercentUsed = [math]::Round(($used / $total) * 100, 2) } catch { $memPercentUsed = 'WMI Failure' } } else { $memPercentUsed = 'Fail' } return $memPercentUsed } # Funtion to put all the gathered information into HTML Function New-ServerHealthHTMLTableCell() { param( $lineitem ) $htmltablecell = $null switch ($($reportline."$lineitem")) { "Success" { $htmltablecell = "<td class=""pass"">$($reportline."$lineitem")</td>" } "Passed" { $htmltablecell = "<td class=""pass"">$($reportline."$lineitem")</td>" } "Pass" { $htmltablecell = "<td class=""pass"">$($reportline."$lineitem")</td>" } "Warn" { $htmltablecell = "<td class=""warn"">$($reportline."$lineitem")</td>" } "Fail" { $htmltablecell = "<td class=""fail"">$($reportline."$lineitem")</td>" } "Failed" { $htmltablecell = "<td class=""fail"">$($reportline."$lineitem")</td>" } "Could not test server uptime." { $htmltablecell = "<td class=""fail"">$($reportline."$lineitem")</td>" } default { $htmltablecell = "<td>$($reportline."$lineitem")</td>" } } return $htmltablecell } if (!($DomainName)) { Write-Host "No domain specified, using all domains in forest" -ForegroundColor Yellow $allDomains = Get-AllDomains $reportFileName = 'forest_health_report_' + (Get-ADForest).name + '_' + $reportFileNameTime + '.html' } else { Write-Host "Domain name specified on cmdline" -ForegroundColor Cyan $allDomains = $DomainName $reportFileName = 'dc_health_report_' + $DomainName + '_' + $reportFileNameTime + '.html' } foreach ($domain in $allDomains) { Write-Host "Testing domain" $domain -ForegroundColor Green $allDomainControllers = Get-AllDomainControllers $domain $allDomainControllers = @($allDomainControllers) $totalDCs = $allDomainControllers.Count $currentDCNumber = 0 foreach ($domainController in $allDomainControllers) { $currentDCNumber++ $stopWatch = [system.diagnostics.stopwatch]::StartNew() Write-Host "Testing domain controller ($currentDCNumber of $totalDCs) $($domainController.HostName)" -ForegroundColor Cyan $DCDiagTestResults = Get-DomainControllerDCDiagTestResults $domainController.HostName $svcResults = Get-DomainControllerServices $domainController.HostName $thisDomainController = [PSCustomObject]@{ Server = ($domainController.HostName).ToLower() Site = $domainController.Site "IPv4 Address" = $domainController.IPv4Address "OS Free Space (GB)" = Get-DomainControllerOSDriveFreeSpaceGB $domainController.HostName "CPU Usage (%)" = Get-DomainControllerCPUUsage $domainController.HostName "Memory Usage (%)" = Get-DomainControllerMemoryUsage $domainController.HostName "Uptime (days)" = Get-DomainControllerUptimeDays $domainController.HostName "NTDS Service" = $svcResults.NTDSService "NetLogon Service" = $svcResults.NETLOGONService "DCDIAG: Connectivity" = $DCDiagTestResults.Connectivity "DCDIAG: Advertising" = $DCDiagTestResults.Advertising "DCDIAG: FrsEvent" = $DCDiagTestResults.FrsEvent "DCDIAG: DFSREvent" = $DCDiagTestResults.DFSREvent "DCDIAG: SysVolCheck" = $DCDiagTestResults.SysVolCheck "DCDIAG: KccEvent" = $DCDiagTestResults.KccEvent "DCDIAG: FSMO " = $DCDiagTestResults.KnowsOfRoleHolders "DCDIAG: NetLogons" = $DCDiagTestResults.NetLogons "DCDIAG: ObjectsReplicated" = $DCDiagTestResults.ObjectsReplicated "DCDIAG: Replications" = $DCDiagTestResults.Replications "DCDIAG: RidManager" = $DCDiagTestResults.RidManager "DCDIAG: Services" = $DCDiagTestResults.Services } $allTestedDomainControllers.Add($thisDomainController) } } # Modified HTML and table creation: Outlook-friendly $htmlhead = @" <html> <body style='font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;font-size:10pt;'> <h1 style='font-size:20px;text-align:left;'>Domain Controller Health Check Report</h1> <h3 style='font-size:14px;text-align:left;'>Generated: $reportTime</h3> "@ $htmltableheader = @" <h3 style='font-size:14px;color:#333;margin-bottom:3px;'>Domain Controller Health Summary</h3> <h3 style='font-size:12px;margin-top:0;font-weight:normal;'>Forest: $((Get-ADForest).Name)</h3> <table border='1' cellpadding='0' cellspacing='0' style='width:100%;border-collapse:collapse;font-size:10pt;'> <tr style='background-color:#f2f2f2;'> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>Server</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>Site</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>IPv4 Address</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>OS Free Space (GB)</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>CPU Usage (%)</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>Memory Usage (%)</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>Uptime (days)</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>NTDS Service</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>NetLogon Service</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: Connectivity</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: Advertising</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: FrsEvent</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: DFSREvent</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: SysVolCheck</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: KccEvent</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: FSMO</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: NetLogons</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: ObjectsReplicated</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: Replications</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: RidManager</th> <th style='border:1px solid #ccc; padding:6px; color:#000; text-align:center;'>DCDIAG: Services</th> </tr> "@ Function New-ServerHealthHTMLTableCell() { param( $lineitem ) $cellValue = $reportline."$lineitem" switch ($cellValue) { "Success" { return "<td style='border:1px solid #ccc;padding:6px; background-color:#6BBF59; color:#000;text-align:center;'>$cellValue</td>" } "Passed" { return "<td style='border:1px solid #ccc;padding:6px; background-color:#6BBF59; color:#000;text-align:center;'>$cellValue</td>" } "Pass" { return "<td style='border:1px solid #ccc;padding:6px; background-color:#6BBF59; color:#000;text-align:center;'>$cellValue</td>" } "Warn" { return "<td style='border:1px solid #ccc;padding:6px; background-color:#FFD966; color:#000;text-align:center;'>$cellValue</td>" } "Fail" { return "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;text-align:center;'>$cellValue</td>" } "Failed" { return "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;text-align:center;'>$cellValue</td>" } "Could not test server uptime." { return "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;'>$cellValue</td>" } default { return "<td style='border:1px solid #ccc;padding:6px;'>$cellValue</td>" } } } $serverhealthhtmltable = "" $serverhealthhtmltable += $htmltableheader foreach ($reportline in $allTestedDomainControllers) { $htmltablerow = "<tr>" $htmltablerow += "<td style='border:1px solid #ccc;padding:6px;text-align:center;'>$($reportline.Server)</td>" $htmltablerow += "<td style='border:1px solid #ccc;padding:6px;text-align:center;'>$($reportline.Site)</td>" $htmltablerow += "<td style='border:1px solid #ccc;padding:6px;text-align:center;'>$($reportline.'IPv4 Address')</td>" # OS Free Space $osFree = $reportline.'OS Free Space (GB)' if ($osFree -is [double] -or $osFree -is [int]) { if ($osFree -lt 20) { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;text-align:center;'>$osFree</td>" # Red (<20GB) } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#6BBF59; color:#000;text-align:center;'>$osFree</td>" # Green (>=20GB) } } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px;text-align:center;'>$osFree</td>" } # color coding CPU Usage $cpu = $reportline.'CPU Usage (%)' if ($cpu -is [double] -or $cpu -is [int]) { if ($cpu -le 75) { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#6BBF59; color:#000;text-align:center;'>$cpu</td>" } elseif ($cpu -le 90) { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#FFD966; color:#000;text-align:center;'>$cpu</td>" } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;text-align:center;'>$cpu</td>" } } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px;text-align:center;'>$cpu</td>" } #color coding Memory Usage $mem = $reportline.'Memory Usage (%)' if ($mem -is [double] -or $mem -is [int]) { if ($mem -le 75) { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#6BBF59; color:#000;text-align:center;'>$mem</td>" } elseif ($mem -le 90) { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#FFD966; color:#000;text-align:center;'>$mem</td>" } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;text-align:center;'>$mem</td>" } } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px;text-align:center;'>$mem</td>" } # color coding Uptime $uptimeDays = $reportline.'Uptime (days)' if ($uptimeDays -eq "CIM Failure" -or $uptimeDays -eq "Fail") { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;'>$uptimeDays</td>" } elseif ($uptimeDays -is [int] -or $uptimeDays -is [double]) { if ($uptimeDays -le 31) { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#6BBF59; color:#000;text-align:center;'>$uptimeDays</td>" } elseif ($uptimeDays -le 45) { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#FFD966; color:#000;text-align:center;'>$uptimeDays</td>" } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px; background-color:#D9534F; color:#fff;text-align:center;'>$uptimeDays</td>" } } else { $htmltablerow += "<td style='border:1px solid #ccc;padding:6px;text-align:center;'>$uptimeDays</td>" } # Filling the Remaining items in HTML $htmltablerow += (New-ServerHealthHTMLTableCell "NTDS Service") $htmltablerow += (New-ServerHealthHTMLTableCell "NetLogon Service") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Connectivity") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Advertising") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: FrsEvent") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: DFSREvent") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: SysVolCheck") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: KccEvent") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: FSMO ") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: NetLogons") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: ObjectsReplicated") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Replications") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: RidManager") $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Services") $htmltablerow += "</tr>" $serverhealthhtmltable += $htmltablerow } $serverhealthhtmltable += "</table>" # Example explanation table $explanationTable = @" <h3 style='font-family: Arial, sans-serif; color: #0056b3;'>Column Reference</h3> <table border='1' cellpadding='0' cellspacing='0' style='border-collapse:collapse; width:45%; font-family:Arial, sans-serif; font-size:12px;'> <thead> <tr style='background-color:#f2f2f2;'> <th style='border:1px solid #ccc; padding:6px; text-align:left;'>Field</th> <th style='border:1px solid #ccc; padding:6px; text-align:left;'>Description</th> </tr> </thead> <tbody> <tr><td style='border:1px solid #ccc; padding:6px;'>Site</td><td style='border:1px solid #ccc; padding:6px;'>The AD site where the domain controller resides.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>IPv4 Address</td><td style='border:1px solid #ccc; padding:6px;'>The IP address of the domain controller.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>OS Free Space (GB)</td><td style='border:1px solid #ccc; padding:6px;'>Available disk space on the system drive (in GB).</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>CPU Usage (%)</td><td style='border:1px solid #ccc; padding:6px;'>Current CPU utilization of the server.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>Memory Usage (%)</td><td style='border:1px solid #ccc; padding:6px;'>Current RAM utilization.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>Uptime (days)</td><td style='border:1px solid #ccc; padding:6px;'>How many days the DC has been running since the last reboot.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>NTDS Service</td><td style='border:1px solid #ccc; padding:6px;'>Whether the AD DS (NTDS) service is running.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>NetLogon Service</td><td style='border:1px solid #ccc; padding:6px;'>Whether the NetLogon service is running.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>Connectivity</td><td style='border:1px solid #ccc; padding:6px;'>Checks basic connectivity between DCs.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>Advertising</td><td style='border:1px solid #ccc; padding:6px;'>Ensures the DC is advertising itself correctly.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>FrsEvent</td><td style='border:1px solid #ccc; padding:6px;'>Checks legacy File Replication Service errors.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>DFSREvent</td><td style='border:1px solid #ccc; padding:6px;'>Checks DFS Replication health for SYSVOL.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>SysVolCheck</td><td style='border:1px solid #ccc; padding:6px;'>Verifies SYSVOL availability.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>KccEvent</td><td style='border:1px solid #ccc; padding:6px;'>Checks KCC (replication topology).</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>FSMO</td><td style='border:1px solid #ccc; padding:6px;'>Confirms the DC knows FSMO role holders.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>NetLogons</td><td style='border:1px solid #ccc; padding:6px;'>Validates secure channel (Netlogon).</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>ObjectsReplicated</td><td style='border:1px solid #ccc; padding:6px;'>Confirms that AD objects replicate properly.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>Replications</td><td style='border:1px solid #ccc; padding:6px;'>Checks replication health between DCs.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>RidManager</td><td style='border:1px solid #ccc; padding:6px;'>Verifies RID Master functionality.</td></tr> <tr><td style='border:1px solid #ccc; padding:6px;'>Services</td><td style='border:1px solid #ccc; padding:6px;'>Checks critical services (DNS, Kerberos, etc.).</td></tr> </tbody> </table> "@ $serverhealthhtmltable += $explanationTable $htmltail = "<p style='font-size:11px; color:#555;'>* DNS test is performed using <code>Resolve-DnsName</code>. This cmdlet is only available from Windows Server 2012 onwards.</p> </body> </html>" $htmlreport = $htmlhead + $serverhealthhtmltable $htmlreport | Out-File $reportFileName -Encoding UTF8 Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -Attachments $reportFileName -Encoding ([System.Text.Encoding]::UTF8) -ErrorAction Stop Write-Host "Email sent successfully." -ForegroundColor Green