skip to Main Content

Active Directory health check with PowerShell script

What is an excellent way to check the Domain Controller health? Perhaps you want to add a new Domain Controller to an existing domain, and before doing that, you want to check the Active Directory health state. Let’s see how to health check Active Directory with an excellent PowerShell script.

Why you want to check Active Directory health

It’s good to check the Domain Controllers health if there are incidents, problems, or changes that you have to apply:

  • There is a problem with Active Directory
  • There are problems between Domain Controllers
  • Before/after a Windows Update on the Domain Controller
  • Before/after installing a new Domain Controller in the organization
  • Before/after a Domain Controller demote

Active Directory health check PowerShell script

The Get-ADHealth.ps1 PowerShell script will check the health of your AD environment and provide you with a report that you can use to identify and resolve any issues:

  1. Server
  2. Site
  3. OS Version
  4. Operation Master Roles
  5. DNS
  6. Ping
  7. Uptime (hrs)
  8. DIT Free Space (%)
  9. OS Free Space (%)
  10. DNS Service
  11. NTDS Service
  12. NetLogon Service
  13. DCDIAG: Advertising
  14. DCDIAG: Replications
  15. DCDIAG: FSMO KnowsOfRoleHolders
  16. DCDIAG: FSMO Check
  17. DCDIAG: Services
  18. Processing Time

Download Active Directory health check PowerShell script

Download and place Get-ADHealth.ps1 PowerShell script on the Domain Controller C:\scripts folder. If you don’t have a scripts folder, create one.

Ensure that the file is unblocked to prevent any errors when running the script. Read more in the article Not digitally signed error when running PowerShell script.

Another option is to copy and paste the below code into Notepad. Give it the name Get-ADHealth.ps1 and place it in the C:\scripts folder.

<#
.SYNOPSIS
Get-ADHealth - Domain Controller Health Check Script.
.DESCRIPTION 
This script performs a list of common health checks to a specific domain, or the entire forest. The results are then compiled into a colour coded HTML report.
.OUTPUTS
The results are currently only output to HTML for email or as an HTML report file, or sent as an SMTP message with an HTML body.
.PARAMETER DomainName
Perform a health check on a specific Active Directory domain.
.PARAMETER ReportFile
Output the report details to a file in the current directory.
.PARAMETER SendEmail
Send the report via email. You have to configure the correct SMTP settings
.EXAMPLE
.\Get-ADHealth.ps1 -ReportFile
Checks all domains and all domain controllers in your current forest and creates a report.
.EXAMPLE
.\Get-ADHealth.ps1 -DomainName alitajran.com -ReportFile
Checks all the domain controllers in the specified domain "alitajran.com" and creates a report.
.EXAMPLE
.\Get-ADHealth.ps1 -DomainName alitajran.com -SendEmail
Checks all the domain controllers in the specified domain "alitajran.com" and sends the resulting report as an email message.
.LINK
alitajran.com/active-directory-health-check-powershell-script
#>

[CmdletBinding()]
Param(
    [Parameter( Mandatory = $false)]
    [string]$DomainName,

    [Parameter( Mandatory = $false)]
    [switch]$ReportFile,
        
    [Parameter( Mandatory = $false)]
    [switch]$SendEmail
)

#...................................
# Global Variables
#...................................

$now = Get-Date
$date = $now.ToShortDateString()
[array]$allDomainControllers = @()
$reportime = Get-Date
$reportemailsubject = "Domain Controller Health Report"

$smtpsettings = @{
    To         = 'email@domain.com'
    From       = 'adhealth@pdomain.com'
    Subject    = "$reportemailsubject - $now"
    SmtpServer = "mail.domain.com"
}

#...................................
# Functions
#...................................

# This fucntion gets all the domains in the forest.
Function Get-AllDomains() {
    Write-Verbose "..running function Get-AllDomains"
    $allDomains = (Get-ADForest).Domains 
    return $allDomains
}

# This function gets all the domain controllers in a specified domain.
Function Get-AllDomainControllers ($DomainNameInput) {
    Write-Verbose "..running function Get-AllDomainControllers" 
    [array]$allDomainControllers = Get-ADDomainController -Filter * -Server $DomainNameInput
    return $allDomainControllers
}

# This function tests the name against DNS.
Function Get-DomainControllerNSLookup($DomainNameInput) {
    Write-Verbose "..running function Get-DomainControllerNSLookup" 
    try {
        $domainControllerNSLookupResult = Resolve-DnsName $DomainNameInput -Type A | select -ExpandProperty IPAddress

        $domainControllerNSLookupResult = 'Success'
    }
    catch {
        $domainControllerNSLookupResult = 'Fail'
    }
    return $domainControllerNSLookupResult
}

# This function tests the connectivity to the domain controller.
Function Get-DomainControllerPingStatus($DomainNameInput) {
    Write-Verbose "..running function Get-DomainControllerPingStatus" 
    If ((Test-Connection $DomainNameInput -Count 1 -quiet) -eq $True) {
        $domainControllerPingStatus = "Success"
    }

    Else {
        $domainControllerPingStatus = 'Fail'
    }
    return $domainControllerPingStatus
}

# This function tests the domain controller uptime.
Function Get-DomainControllerUpTime($DomainNameInput) {
    Write-Verbose "..running function Get-DomainControllerUpTime" 

    If ((Test-Connection $DomainNameInput -Count 1 -quiet) -eq $True) {
        try {
            $W32OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $DomainNameInput -ErrorAction SilentlyContinue
            $timespan = $W32OS.ConvertToDateTime($W32OS.LocalDateTime) - $W32OS.ConvertToDateTime($W32OS.LastBootUpTime)
            [int]$uptime = "{0:00}" -f $timespan.TotalHours
        }
        catch [exception] {
            $uptime = 'WMI Failure'
        }

    }

    Else {
        $uptime = '0'
    }
    return $uptime  
}

# This function checks the DIT file drive space.
Function Get-DITFileDriveSpace($DomainNameInput) {
    Write-Verbose "..running function Get-DITFileDriveSpace" 

    If ((Test-Connection $DomainNameInput -Count 1 -quiet) -eq $True) {
        try {
            $key = "SYSTEM\CurrentControlSet\Services\NTDS\Parameters"
            $valuename = "DSA Database file"
            $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $DomainNameInput)
            $regkey = $reg.opensubkey($key)
            $NTDSPath = $regkey.getvalue($valuename)
            $NTDSPathDrive = $NTDSPath.ToString().Substring(0, 2)
            $NTDSPathFilter = '"' + 'DeviceID=' + "'" + $NTDSPathDrive + "'" + '"'
            $NTDSDiskDrive = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $DomainNameInput -ErrorAction SilentlyContinue | ? { $_.DeviceID -eq $NTDSPathDrive }
            $NTDSPercentFree = [math]::Round($NTDSDiskDrive.FreeSpace / $NTDSDiskDrive.Size * 100)
        }
        catch [exception] {
            $NTDSPercentFree = 'WMI Failure'
        }
    }

    Else {
        $NTDSPercentFree = '0'
    }
    return $NTDSPercentFree 
}

# This function checks the DNS, NTDS and Netlogon services.
Function Get-DomainControllerServices($DomainNameInput) {
    Write-Verbose "..running function DomainControllerServices"
    $thisDomainControllerServicesTestResult = New-Object PSObject
    $thisDomainControllerServicesTestResult | Add-Member NoteProperty -name DNSService -Value $null
    $thisDomainControllerServicesTestResult | Add-Member NoteProperty -name NTDSService -Value $null
    $thisDomainControllerServicesTestResult | Add-Member NoteProperty -name NETLOGONService -Value $null

    If ((Test-Connection $DomainNameInput -Count 1 -quiet) -eq $True) {
        If ((Get-Service -ComputerName $DomainNameInput -Name DNS -ErrorAction SilentlyContinue).Status -eq 'Running') {
            $thisDomainControllerServicesTestResult.DNSService = 'Success'
        }
        Else {
            $thisDomainControllerServicesTestResult.DNSService = 'Fail'
        }
        If ((Get-Service -ComputerName $DomainNameInput -Name NTDS -ErrorAction SilentlyContinue).Status -eq 'Running') {
            $thisDomainControllerServicesTestResult.NTDSService = 'Success'
        }
        Else {
            $thisDomainControllerServicesTestResult.NTDSService = 'Fail'
        }
        If ((Get-Service -ComputerName $DomainNameInput -Name netlogon -ErrorAction SilentlyContinue).Status -eq 'Running') {
            $thisDomainControllerServicesTestResult.NETLOGONService = 'Success'
        }
        Else {
            $thisDomainControllerServicesTestResult.NETLOGONService = 'Fail'
        }
    }

    Else {
        $thisDomainControllerServicesTestResult.DNSService = 'Fail'
        $thisDomainControllerServicesTestResult.NTDSService = 'Fail'
        $thisDomainControllerServicesTestResult.NETLOGONService = 'Fail'
    }
    return $thisDomainControllerServicesTestResult
} 

# This function runs the five DCDiag tests and saves them in a variable for later processing.
Function Get-DomainControllerDCDiagTestResults($DomainNameInput) {
    Write-Verbose "..running function Get-DomainControllerDCDiagTestResults"

    $DCDiagTestResults = New-Object Object
    If ((Test-Connection $DomainNameInput -Count 1 -quiet) -eq $True) {

        $DCDiagTest = (Dcdiag.exe /s:$DomainNameInput /test:services /test:FSMOCheck /test:KnowsOfRoleHolders /test:Advertising /test:Replications) -split ('[\r\n]')

        $DCDiagTestResults | Add-Member -Type NoteProperty -Name "ServerName" -Value $DomainNameInput
        $DCDiagTest | % {
            Switch -RegEx ($_) {
                "Starting" { $TestName = ($_ -Replace ".*Starting test: ").Trim() }
                "passed test|failed test" {
                    If ($_ -Match "passed test") {
                        $TestStatus = "Passed"
                        # $TestName
                        # $_
                    }
                    Else {
                        $TestStatus = "Failed"
                        # $TestName
                        # $_
                    }
                }
            } 
            If ($TestName -ne $Null -And $TestStatus -ne $Null) {
                $DCDiagTestResults | Add-Member -Name $("$TestName".Trim()) -Value $TestStatus -Type NoteProperty -force
                $TestName = $Null; $TestStatus = $Null
            }
        }
        return $DCDiagTestResults
    }

    Else {
        $DCDiagTestResults | Add-Member -Type NoteProperty -Name "ServerName" -Value $DomainNameInput
        $DCDiagTestResults | Add-Member -Name Replications -Value 'Failed' -Type NoteProperty -force 
        $DCDiagTestResults | Add-Member -Name Advertising -Value 'Failed' -Type NoteProperty -force 
        $DCDiagTestResults | Add-Member -Name KnowsOfRoleHolders -Value 'Failed' -Type NoteProperty -force
        $DCDiagTestResults | Add-Member -Name FSMOCheck -Value 'Failed' -Type NoteProperty -force
        $DCDiagTestResults | Add-Member -Name Services -Value 'Failed' -Type NoteProperty -force 
    }
    return $DCDiagTestResults
}

# This function checks the server OS version.
Function Get-DomainControllerOSVersion ($DomainNameInput) {
    Write-Verbose "..running function Get-DomainControllerOSVersion"
    $W32OSVersion = (Get-WmiObject -Class Win32_OperatingSystem -ComputerName $DomainNameInput -ErrorAction SilentlyContinue).Caption
    return $W32OSVersion
}

# This function checks the free space on the OS drive
Function Get-DomainControllerOSDriveFreeSpace ($DomainNameInput) {
    Write-Verbose "..running function Get-DomainControllerOSDriveFreeSpace"

    If ((Test-Connection $DomainNameInput -Count 1 -quiet) -eq $True) {
        try {
            $thisOSDriveLetter = (Get-WmiObject Win32_OperatingSystem -ComputerName $DomainNameInput -ErrorAction SilentlyContinue).SystemDrive
            $thisOSPathFilter = '"' + 'DeviceID=' + "'" + $thisOSDriveLetter + "'" + '"'
            $thisOSDiskDrive = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $DomainNameInput -ErrorAction SilentlyContinue | ? { $_.DeviceID -eq $thisOSDriveLetter }
            $thisOSPercentFree = [math]::Round($thisOSDiskDrive.FreeSpace / $thisOSDiskDrive.Size * 100)
        }

        catch [exception] {
            $thisOSPercentFree = 'WMI Failure'
        }
    }
    return $thisOSPercentFree
}

# This function generates HTML code from the results of the above functions.
Function New-ServerHealthHTMLTableCell() {
    param( $lineitem )
    $htmltablecell = $null

    switch ($($reportline."$lineitem")) {
        $success { $htmltablecell = "<td class=""pass"">$($reportline."$lineitem")</td>" }
        "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>" }
        "Access Denied" { $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>" }
        "Could not test service health. " { $htmltablecell = "<td class=""warn"">$($reportline."$lineitem")</td>" }
        "Unknown" { $htmltablecell = "<td class=""warn"">$($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 + '.html'
}

Else {
    Write-Host "..domain name specified on cmdline"
    $allDomains = $DomainName
    $reportFileName = 'dc_health_report_' + $DomainName + '.html'
}

foreach ($domain in $allDomains) {
    Write-Host "..testing domain" $domain -ForegroundColor Green
    [array]$allDomainControllers = Get-AllDomainControllers $domain
    $totalDCtoProcessCounter = $allDomainControllers.Count
    $totalDCProcessCount = $allDomainControllers.Count 

    foreach ($domainController in $allDomainControllers) {
        $stopWatch = [system.diagnostics.stopwatch]::StartNew()
        Write-Host "..testing domain controller" "(${totalDCtoProcessCounter} of ${totalDCProcessCount})" $domainController.HostName -ForegroundColor Cyan 
        $DCDiagTestResults = Get-DomainControllerDCDiagTestResults $domainController.HostName
        $thisDomainController = New-Object PSObject
        $thisDomainController | Add-Member NoteProperty -name Server -Value $null
        $thisDomainController | Add-Member NoteProperty -name Site -Value $null
        $thisDomainController | Add-Member NoteProperty -name "OS Version" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "Operation Master Roles" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DNS" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "Ping" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "Uptime (hrs)" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DIT Free Space (%)" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "OS Free Space (%)" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DNS Service" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "NTDS Service" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "NetLogon Service" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DCDIAG: Advertising" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DCDIAG: Replications" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DCDIAG: FSMO KnowsOfRoleHolders" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DCDIAG: FSMO Check" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "DCDIAG: Services" -Value $null
        $thisDomainController | Add-Member NoteProperty -name "Processing Time" -Value $null
        $OFS = "`r`n"
        $thisDomainController.Server = ($domainController.HostName).ToLower()
        $thisDomainController.Site = $domainController.Site
        $thisDomainController."OS Version" = (Get-DomainControllerOSVersion $domainController.hostname)
        $thisDomainController."Operation Master Roles" = $domainController.OperationMasterRoles
        $thisDomainController.DNS = Get-DomainControllerNSLookup $domainController.HostName
        $thisDomainController.Ping = Get-DomainControllerPingStatus $domainController.HostName
        $thisDomainController."Uptime (hrs)" = Get-DomainControllerUpTime $domainController.HostName
        $thisDomainController."DIT Free Space (%)" = Get-DITFileDriveSpace $domainController.HostName
        $thisDomainController."OS Free Space (%)" = Get-DomainControllerOSDriveFreeSpace $domainController.HostName
        $thisDomainController."DNS Service" = (Get-DomainControllerServices $domainController.HostName).DNSService
        $thisDomainController."NTDS Service" = (Get-DomainControllerServices $domainController.HostName).NTDSService
        $thisDomainController."NetLogon Service" = (Get-DomainControllerServices $domainController.HostName).NETLOGONService
        $thisDomainController."DCDIAG: Replications" = $DCDiagTestResults.Replications
        $thisDomainController."DCDIAG: Advertising" = $DCDiagTestResults.Advertising
        $thisDomainController."DCDIAG: FSMO KnowsOfRoleHolders" = $DCDiagTestResults.KnowsOfRoleHolders
        $thisDomainController."DCDIAG: FSMO Check" = $DCDiagTestResults.FSMOCheck
        $thisDomainController."DCDIAG: Services" = $DCDiagTestResults.Services
        $thisDomainController."Processing Time" = $stopWatch.Elapsed.Seconds
        [array]$allTestedDomainControllers += $thisDomainController
        $totalDCtoProcessCounter -- 
    }

}

# Common HTML head and styles
$htmlhead = "<html>
                <style>
                BODY{font-family: Arial; font-size: 8pt;}
                H1{font-size: 16px;}
                H2{font-size: 14px;}
                H3{font-size: 12px;}
                TABLE{border: 1px solid black; border-collapse: collapse; font-size: 8pt;}
                TH{border: 1px solid black; background: #dddddd; padding: 5px; color: #000000;}
                TD{border: 1px solid black; padding: 5px; }
                td.pass{background: #7FFF00;}
                td.warn{background: #FFE600;}
                td.fail{background: #FF0000; color: #ffffff;}
                td.info{background: #85D4FF;}
                </style>
                <body>
                <h1 align=""left"">Domain Controller Health Check Report</h1>
                <h3 align=""left"">Generated: $reportime</h3>"
                   
# Domain Controller Health Report Table Header
$htmltableheader = "<h3>Domain Controller Health Summary</h3>
                        <h3>Forest: $((Get-ADForest).Name)</h3>
                        <p>
                        <table>
                        <tr>
                        <th>Server</th>
                        <th>Site</th>
                        <th>OS Version</th>
                        <th>Operation Master Roles</th>
                        <th>DNS</th>
                        <th>Ping</th>
                        <th>Uptime (hrs)</th>
                        <th>DIT Free Space (%)</th>
                        <th>OS Free Space (%)</th>
                        <th>DNS Service</th>
                        <th>NTDS Service</th>
                        <th>NetLogon Service</th>
                        <th>DCDIAG: Advertising</th>
                        <th>DCDIAG: Replications</th>
                        <th>DCDIAG: FSMO KnowsOfRoleHolders</th>
                        <th>DCDIAG: FSMO Check</th>
                        <th>DCDIAG: Services</th>
                        <th>Processing Time</th>
                        </tr>"

# Domain Controller Health Report Table
$serverhealthhtmltable = $serverhealthhtmltable + $htmltableheader

# This section will process through the $allTestedDomainControllers array object and create and colour the HTML table based on certain conditions.
foreach ($reportline in $allTestedDomainControllers) {
      
    if (Test-Path variable:fsmoRoleHTML) {
        Remove-Variable fsmoRoleHTML
    }

    if (($reportline."Operation Master Roles") -gt 0) {
        foreach ($line in $reportline."Operation Master Roles") {
            if ($line.count -gt 0) {
                [array]$fsmoRoleHTML += $line.ToString() + '<br>'
            }
        }
    }

    else {
        $fsmoRoleHTML += 'None<br>'
    }

    $htmltablerow = "<tr>"
    $htmltablerow += "<td>$($reportline.server)</td>"
    $htmltablerow += "<td>$($reportline.site)</td>"
    $htmltablerow += "<td>$($reportline."OS Version")</td>"
    $htmltablerow += "<td>$($fsmoRoleHTML)</td>"
    $htmltablerow += (New-ServerHealthHTMLTableCell "DNS" )                  
    $htmltablerow += (New-ServerHealthHTMLTableCell "Ping")

    if ($($reportline."uptime (hrs)") -eq "WMI Failure") {
        $htmltablerow += "<td class=""warn"">Could not test server uptime.</td>"        
    }
    elseif ($($reportline."Uptime (hrs)") -eq $string17) {
        $htmltablerow += "<td class=""warn"">$string17</td>"
    }
    else {
        $hours = [int]$($reportline."Uptime (hrs)")
        if ($hours -le 24) {
            $htmltablerow += "<td class=""warn"">$hours</td>"
        }
        else {
            $htmltablerow += "<td class=""pass"">$hours</td>"
        }
    }

    $space = $reportline."DIT Free Space (%)"
        
    if ($space -eq "WMI Failure") {
        $htmltablerow += "<td class=""warn"">Could not test server free space.</td>"        
    }
    elseif ($space -le 30) {
        $htmltablerow += "<td class=""warn"">$space</td>"
    }
    else {
        $htmltablerow += "<td class=""pass"">$space</td>"
    }

    $osSpace = $reportline."OS Free Space (%)"
        
    if ($osSpace -eq "WMI Failure") {
        $htmltablerow += "<td class=""warn"">Could not test server free space.</td>"        
    }
    elseif ($osSpace -le 30) {
        $htmltablerow += "<td class=""warn"">$osSpace</td>"
    }
    else {
        $htmltablerow += "<td class=""pass"">$osSpace</td>"
    }

    $htmltablerow += (New-ServerHealthHTMLTableCell "DNS Service")
    $htmltablerow += (New-ServerHealthHTMLTableCell "NTDS Service")
    $htmltablerow += (New-ServerHealthHTMLTableCell "NetLogon Service")
    $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Advertising")
    $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Replications")
    $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: FSMO KnowsOfRoleHolders")
    $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: FSMO Check")
    $htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Services")
          
    $averageProcessingTime = ($allTestedDomainControllers | measure -Property "Processing Time" -Average).Average
    if ($($reportline."Processing Time") -gt $averageProcessingTime) {
        $htmltablerow += "<td class=""warn"">$($reportline."Processing Time")</td>"        
    }
    elseif ($($reportline."Processing Time") -le $averageProcessingTime) {
        $htmltablerow += "<td class=""pass"">$($reportline."Processing Time")</td>"
    }

    [array]$serverhealthhtmltable = $serverhealthhtmltable + $htmltablerow
}

$serverhealthhtmltable = $serverhealthhtmltable + "</table></p>"

$htmltail = "* Windows 2003 Domain Controllers do not have the NTDS Service running. Failing this test is normal for that version of Windows.<br>
    * DNS test is performed using Resolve-DnsName. This cmdlet is only available from Windows 2012 onwards.
                </body>
                </html>"

$htmlreport = $htmlhead + $serversummaryhtml + $dagsummaryhtml + $serverhealthhtmltable + $dagreportbody + $htmltail

if ($ReportFile) {
    $htmlreport | Out-File $reportFileName -Encoding UTF8
}

if ($SendEmail) {
    # Send email message
    Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF8)

}

Create scheduled task

Suppose you want the Get-ADHealth.ps1 PowerShell script to automatically run and create the AD health report. Read the article Configure scheduled task.

Configure SMTP relay

Do you want the Get-ADHealth.ps1 PowerShell script to send the report by email? Configure the SMTP settings in lines 49-53 in the PowerShell script. Without that, it is not able to send an email.

Read the below articles on how to configure an SMTP relay:

Create Active Directory health report

To generate an Active Directory health report, go through the below steps:

  1. Sign in to a Domain Controller
  2. Run PowerShell as administrator
  3. Change directory path to C:\scripts
  4. Run .\Get-ADHealth.ps1 -ReportFile
PS C:\> cd C:\scripts
PS C:\scripts> .\Get-ADHealth.ps1 -ReportFile

This is how it looks in our example.

The Get-ADHealth.ps1 PowerShell script will generate an HTML report file. The file is generated in the same directory of the script.

In this example, it’s the folder C:\scripts.

Active Directory health check PowerShell script check files

Open the health report.

The Domain Controllers DC01-2019 and DC02-2019 are reachable, and all tests are passed.

Active Directory health check PowerShell script report

Let’s shut down Domain Controller DC02-2019, run the script, and check the report status.

The health report will show a fail state on most tests, which is the correct behavior.

Active Directory health check PowerShell script report failed

That’s it!

Read more: Get all Domain Controllers with PowerShell »

Conclusion

You learned how to check Active Directory health with the Get-ADHealth.ps1 PowerShell script. The Active Directory Health check PowerShell script will check the Domain Controllers and create a report, which is very useful to see if the health is in a good state.

Did you enjoy this article? You may also like Check TLS settings on Windows Server with PowerShell script. Don’t forget to follow us and share this article.

ALI TAJRAN

ALI TAJRAN

ALI TAJRAN is a passionate IT Architect, IT Consultant, and Microsoft Certified Trainer. He started Information Technology at a very young age, and his goal is to teach and inspire others. Read more »

This Post Has 7 Comments

  1. Hi, in case PRC is disabled for security reason output will be FAILED right?
    BTW good job!

  2. Hi Ali
    Thanks for your good work !!

    In the report I get 4 tables.
    1. table with all DC’s
    2. table with all DC’s twice
    3. table with all DC’s 3 times
    4. table with all DC’s 4 times

    Any idea why?
    Thanks
    Joerg

  3. Thank you! I needed this script. You continue to be ahead of my needs. Keep up the good work! I enjoy website so much!

  4. Hello Ali,
    I will use your Script to check daily our domain controller. What do mean with part 18. processing time?

    Thanks and regards
    Mike

Leave a Reply

Your email address will not be published. Required fields are marked *