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
  • Email address and SMTP Address

Please fill the following according to your environment

  • $smtphost – SMTP Host of your Domain
  • $from – the email address which is going to be used to send emails
  • $email1 – the email address which is going to recieve the emails
###################################################################################################################################
#       Author: Karanth
#       Modified : 19/6/2025
#       Satus: DCdiag Test(Replication,sysvol,Services),CPU Utilization,Memory utilization,Lsass Handle Count,LDAP Service Status
#       Description: AD Health Status
####################################################################################################################################
###########################Define Variables#########################################################################################
$reportpath = ".\ADReport.htm" 
if((test-path $reportpath) -like $false)
{
new-item $reportpath -type file
}
$smtphost = "to be added" 
$from = "to be added" 
$email1 = "to be added" 

$timeout = "60"
###############################HTml Report Content############################
$report = $reportpath
Clear-Content $report 
Add-Content $report "<html>" 
Add-Content $report "<head>" 
Add-Content $report "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>" 
Add-Content $report '<title>AD Status Report</title>' 
add-content $report '<STYLE TYPE="text/css">' 
add-content $report  "<!--" 
add-content $report  "td {" 
add-content $report  "font-family: Calibri;" 
add-content $report  "font-size: 13px;" 
add-content $report  "border-top: 1px solid #999999;" 
add-content $report  "border-right: 1px solid #999999;" 
add-content $report  "border-bottom: 1px solid #999999;" 
add-content $report  "border-left: 1px solid #999999;" 
add-content $report  "padding-top: 0px;" 
add-content $report  "padding-right: 0px;" 
add-content $report  "padding-bottom: 0px;" 
add-content $report  "padding-left: 0px;" 
add-content $report  "}" 
add-content $report  "body {" 
add-content $report  "margin-left: 5px;" 
add-content $report  "margin-top: 5px;" 
add-content $report  "margin-right: 0px;" 
add-content $report  "margin-bottom: 10px;" 
add-content $report  "" 
add-content $report  "table {" 
add-content $report  "border: thin solid #000000;" 
add-content $report  "}" 
add-content $report  "-->" 
add-content $report  "</style>" 
Add-Content $report "</head>" 
Add-Content $report "<body>" 
add-content $report  "<table width='100%'>" 
add-content $report  "<tr bgcolor='#DF0101'>" 
add-content $report  "<td colspan='7' height='25' align='center'>" 
add-content $report  "<font face='Calibri' color='white' size='4'><strong>Active Directory Health Check</strong></font>" 
add-content $report  "</td>" 
add-content $report  "</tr>" 
add-content $report  "</table>" 
add-content $report  "<table width='100%'>" 
Add-Content $report  "<tr bgcolor='#0B0B3B' height='30'>" 
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>Domain Controller</B></td>" 
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>Netlogons Test</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>Replication Test</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>Advertising Test</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>FSMOCheck Test</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>KCCCheck Test</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>DFSRCheck Test</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>Ldap service Status(TCP)</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>Lsass Handle Count</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>CPU Utilization %</B></td>"
Add-Content $report  "<td width='9%' align='center' style='color:white'><B>Memory utilization %</B></td>"
 
Add-Content $report "</tr>" 

#####################################Get ALL DC Servers#################################

              Import-module ActiveDirectory   
              $getForest = [system.directoryservices.activedirectory.Forest]::GetCurrentForest()
			  $DC = $getForest.domains | ForEach-Object {$_.DomainControllers} | ForEach-Object {$_.Name}

        ###################################Ping Test##############################################

              $Identity = $DC

              Add-Content $report "<tr>"
              if ( Test-Connection -ComputerName $DC -Count 1 -ErrorAction SilentlyContinue ) {
              Write-Host $DC `t $DC `t Ping Success -ForegroundColor Green
 
		      Add-Content $report "<td bgcolor= 'GainsBoro' align=center>  <B> $Identity</B></td>" 
         


               ####################Netlogons status##################
               add-type -AssemblyName microsoft.visualbasic 
               $cmp = "microsoft.visualbasic.strings" -as [type]
               $sysvol = start-job -scriptblock {dcdiag /test:netlogons /s:$($args[0])} -ArgumentList $DC
               wait-job $sysvol -timeout $timeout
               if($sysvol.state -like "Running")
               {
               Write-Host $DC `t Netlogons Test TimeOut -ForegroundColor Yellow
               Add-Content $report "<td bgcolor= 'Yellow' align=center><B>NetlogonsTimeout</B></td>"
               stop-job $sysvol
               }
               else
               {
               $sysvol1 = Receive-job $sysvol
               if($cmp::instr($sysvol1, "passed test NetLogons"))
                  {
                  Write-Host $DC `t Netlogons Test passed -ForegroundColor Green
                  Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>Netlogons Passed</B></td>"
                  }
               else
                  {
                  Write-Host $DC `t Netlogons Test Failed -ForegroundColor Red
                  Add-Content $report "<td bgcolor= 'Red'  height='25' align=center><B>Netlogons Fail</B></td>"
                  }
                }
               
               ####################Replications status##################
               add-type -AssemblyName microsoft.visualbasic 
               $cmp = "microsoft.visualbasic.strings" -as [type]
               $sysvol = start-job -scriptblock {dcdiag /test:Replications /s:$($args[0])} -ArgumentList $DC
               wait-job $sysvol -timeout $timeout
               if($sysvol.state -like "Running")
               {
               Write-Host $DC `t Replications Test TimeOut -ForegroundColor Yellow
               Add-Content $report "<td bgcolor= 'Yellow' align=center><B>ReplicationsTimeout</B></td>"
               stop-job $sysvol
               }
               else
               {
               $sysvol1 = Receive-job $sysvol
               if($cmp::instr($sysvol1, "passed test Replications"))
                  {
                  Write-Host $DC `t Replications Test passed -ForegroundColor Green
                  Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>Replications Passed</B></td>"
                  }
               else
                  {
                  Write-Host $DC `t Replications Test Failed -ForegroundColor Red
                  Add-Content $report "<td bgcolor= 'Red'  height='25' align=center><B>Replications Fail</B></td>"
                  }
                }
               
	           ####################Advertising status##################
               add-type -AssemblyName microsoft.visualbasic 
               $cmp = "microsoft.visualbasic.strings" -as [type]
               $sysvol = start-job -scriptblock {dcdiag /test:Advertising /s:$($args[0])} -ArgumentList $DC
               wait-job $sysvol -timeout $timeout
               if($sysvol.state -like "Running")
               {
               Write-Host $DC `t Advertising Test TimeOut -ForegroundColor Yellow
               Add-Content $report "<td bgcolor= 'Yellow' align=center><B>AdvertisingTimeout</B></td>"
               stop-job $sysvol
               }
               else
               {
               $sysvol1 = Receive-job $sysvol
               if($cmp::instr($sysvol1, "passed test Advertising"))
                  {
                  Write-Host $DC `t Advertising Test passed -ForegroundColor Green
                  Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>Advertising Passed</B></td>"
                  }
               else
                  {
                  Write-Host $DC `t Advertising Test Failed -ForegroundColor Red
                  Add-Content $report "<td bgcolor= 'Red'  height='25' align=center><B>Advertising Fail</B></td>"
                  }
                }
               
	           ####################FSMOCheck status##################
               add-type -AssemblyName microsoft.visualbasic 
               $cmp = "microsoft.visualbasic.strings" -as [type]
               $sysvol = start-job -scriptblock {dcdiag /test:FSMOCheck /s:$($args[0])} -ArgumentList $DC
               wait-job $sysvol -timeout $timeout
               if($sysvol.state -like "Running")
               {
               Write-Host $DC `t FSMOCheck Test TimeOut -ForegroundColor Yellow
               Add-Content $report "<td bgcolor= 'Yellow' align=center><B>FSMOCheckTimeout</B></td>"
               stop-job $sysvol
               }
               else
               {
               $sysvol1 = Receive-job $sysvol
               $outputText = ($sysvol1 -join " ") -replace '\s+', ' '  # Normalize for multiline match

				if ($outputText -match "passed test FsmoCheck") {
				Write-Host "$DC`tFSMOCheck Test passed" -ForegroundColor Green
				Add-Content $report "<td bgcolor='Aquamarine' height='25' align='center'><b>FSMOCheck Passed</b></td>"
				} else {
				Write-Host "$DC`tFSMOCheck Test Failed" -ForegroundColor Red
				Add-Content $report "<td bgcolor='Red' height='25' align='center'><b>FSMOCheck Fail</b></td>"
				}
				}
             
               ####################KCCheck status##################
               add-type -AssemblyName microsoft.visualbasic 
               $cmp = "microsoft.visualbasic.strings" -as [type]
               $sysvol = start-job -scriptblock {dcdiag /test:KccEvent /s:$($args[0])} -ArgumentList $DC
               wait-job $sysvol -timeout $timeout
               if($sysvol.state -like "Running")
               {
               Write-Host $DC `t KccEvent Test TimeOut -ForegroundColor Yellow
               Add-Content $report "<td bgcolor= 'Yellow' align=center><B>KccEventTimeout</B></td>"
               stop-job $sysvol
               }
               else
               {
               $sysvol1 = Receive-job $sysvol
               if($cmp::instr($sysvol1, "passed test KccEvent"))
                  {
                  Write-Host $DC `t KccEvent Test passed -ForegroundColor Green
                  Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>KccEvent Passed</B></td>"
                  }
               else
                  {
                  Write-Host $DC `t KccEvent Test Failed -ForegroundColor Red
                  Add-Content $report "<td bgcolor= 'Red'  height='25' align=center><B>KccEvent Fail</B></td>"
                  }
                }
               
	           ####################DFSREvent status##################
               add-type -AssemblyName microsoft.visualbasic 
               $cmp = "microsoft.visualbasic.strings" -as [type]
               $sysvol = start-job -scriptblock {dcdiag /test:DFSREvent /s:$($args[0])} -ArgumentList $DC
               wait-job $sysvol -timeout $timeout
               if($sysvol.state -like "Running")
               {
               Write-Host $DC `t DFSREvent Test TimeOut -ForegroundColor Yellow
               Add-Content $report "<td bgcolor= 'Yellow' align=center><B>DFSREventTimeout</B></td>"
               stop-job $sysvol
               }
               else
               {
               $sysvol1 = Receive-job $sysvol
               if($cmp::instr($sysvol1, "passed test DFSREvent"))
                  {
                  Write-Host $DC `t DFSREvent Test passed -ForegroundColor Green
                  Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>DFSREvent Passed</B></td>"
                  }
               else
                  {
                  Write-Host $DC `t DFSREvent Test Failed -ForegroundColor Red
                  Add-Content $report "<td bgcolor= 'Red'  height='25' align=center><B>DFSREvent Fail</B></td>"
                  }
                }
               
               ####################LDAP Service status(TCP)##################

               PortQry.exe -n $DC -p tcp -e 389 > C:\Script\results.txt
               $value = get-content -path C:\script\results.txt | where-object {$_ -like "*LISTENING*"}
               $split1 = $value.trim(":")
               $split2 = $split1.Split(":")[1] 
               $LDAPServiceStatus = $split2.trim()  
               if ($LDAPServiceStatus -eq "LISTENING")
               {
                Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>$LDAPServiceStatus</B></td>"
               }

               else
               {
                Add-Content $report "<td bgcolor= 'Yellow'  height='25' align=center><B>$LDAPServiceStatus</B></td>"
               }
             
              ####################################Lsass handlecount,CPu,Memory utilization #################################
              #$Result = @()  
              $Lsass = get-process -computername $DC lsass | format-list | findstr "Handles"; $Lsass2 = $Lsass.Split(":")[1]
              $Lsass_Count = $Lsass2.trim()
              $AVGProc = Get-WmiObject -computername $DC win32_processor | Measure-Object -property LoadPercentage -Average | Select Average 
              $OS = gwmi -Class win32_operatingsystem -computername $DC | 
              Select-Object @{Name = "MemoryUsage"; Expression = {“{0:N2}” -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize) }} 
              $CPULoad = "$($AVGProc.Average)%"
              $MemLoad = "$($OS.MemoryUsage)%" 
              Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>$Lsass_Count</B></td>"

              If ($entry.cpuload -ge 80 -or ($entry.memload -ge 80))
               {
              Write-Host $DC `t $CPULoad -ge 80 -ForegroundColor Red
	          Write-Host $DC `t $MemLoad -ge 80 -ForegroundColor Red	
              Add-Content $report "<td bgcolor= 'Red'  height='25' align=center><B>$CPULoad</B></td>"  
	          Add-Content $report "<td bgcolor= 'Red'  height='25' align=center><B>$MemLoad</B></td>"
              } 
              ElseIf ($entry.cpuload -lt 80 -or ($entry.memload -lt 80))
              {
              write-Host $DC `t $CPULoad -lt 80 -ForegroundColor Green
              write-Host $DC `t $MemLoad -lt 80 -ForegroundColor Green
              Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>$CPULoad</B></td>"
              Add-Content $report "<td bgcolor= 'Aquamarine'  height='25' align=center><B>$MemLoad</B></td>"
              }                
              ##################################################################################################
              } 
              else
              {
              Write-Host $DC `t $DC `t Ping Fail -ForegroundColor Red
              Add-Content $report "<td bgcolor= 'GainsBoro' align=center>  <B> $Identity</B></td>"
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>Netlogons Fail</B></td>" 
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>Replications Fail</B></td>" 
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>Advertising Fail</B></td>" 
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>FSMOCheck Fail</B></td>"
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>KccEvent Fail</B></td>"
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>DFSRCheck Fail</B></td>"
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>Not Captured</B></td>"
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>Not Captured</B></td>"
		      Add-Content $report "<td bgcolor= 'Red'  height='25' align=center>  <B>Not Captured</B></td>"
              }         
              }
              Add-Content $report "</tr>"
############################################Close HTMl Tables###########################
Add-content $report  "</table>" 
Add-Content $report "</body>" 
Add-Content $report "</html>" 
########################################################################################
#############################################Send Email#################################
Add-Content .\ADreport.htm "<BR>"
Add-Content .\ADreport.htm "<BR>"
Add-Content .\ADreport.htm "<BR>"
Add-Content .\ADreport.htm "<BR>"
Add-Content .\ADreport.htm "<BR>"
Add-Content .\ADreport.htm "<BR>"
Add-Content .\ADreport.htm "<BR>"
Add-content $report "<font face='Calibri' Size='3'>"
Add-Content .\ADreport.htm "<h3>Explanation for Healthcheck Parameters</h3>"
add-content .\ADreport.htm "<table font face='Calibri' Size='3' width='90%'>" 
add-content .\ADreport.htm "<tr><td height='20' width='10%'><b>Parameter</b></td><td><b>Explanation</b></td></tr>"
add-content .\ADreport.htm "<tr><td height='20'>Netlogon Test</td><td>This will verify that the proper permissions are set for SYSVOL replication </td></tr>"
add-content .\ADreport.htm "<tr><td height='20'>Replication Test</td><td>This test is to monitor the replication</td></tr>"
add-content .\ADreport.htm "<tr><td height='20'>Advertising Test</td><td>This Checks whether domain controller advertises itself in the roles that it should be capable of performing. This test fails if the Netlogon Service has stopped or failed to start</td></tr>"
add-content .\ADreport.htm "<tr><td height='20'>FSMOCheckTest</td><td>This Checks that the domain controller can contact a Kerberos Key Distribution Center (KDC), a time server, a preferred time server, a primary domain controller (PDC), and a global catalog server</td></tr>"
add-content .\ADreport.htm "<tr><td height='20'>KCCheckTest</td><td>This Checks that the KCC is completing without errors</td></tr>"
add-content .\ADreport.htm "<tr><td height='20'>DFSREventTest</td><td>This Checks to see if there are any errors in the file replication systems</td></tr>"
add-content .\ADreport.htm "<tr><td height='20'>Lsass Handlecount   </td><td>This Gets the number of handles opened by the Lsass process</td></tr>"
add-content .\ADreport.htm "</table>"
Add-content $report "</font>"
$subject = "Daily Active Directory Health and Performance Report" 
$body = Get-Content ".\ADreport.htm" 
$smtp= New-Object System.Net.Mail.SmtpClient $smtphost 
$msg = New-Object System.Net.Mail.MailMessage 
$msg.To.Add($email1)
$msg.from = $from
$msg.subject = $subject
$msg.body = $body 
$msg.isBodyhtml = $true 
$smtp.send($msg) 

########################################################################################
########################################################################################

Leave a Comment