Domain Controllers NTP Report

In this article, we will prepare a report with powershell script in active directory environment.
What will be in the content of this report.

  • Domain
  • Domain Controller
  • FSMO
  • NTP Source
  • Last Successful Sync Time
  • Stratum
  • Type

I am sharing an example screenshot

The script used is as follows

# ===================================
# NTP Settings Report - MSFTADVOCATE.COM
# ===================================

Import-Module ActiveDirectory

# Get Domain Controllers
$domainControllers = Get-ADDomainController -Filter *

# Initialize Report
$ntpReport = @()

foreach ($dc in $domainControllers) {
    try {
        Write-Host "Checking NTP for $($dc.HostName)..." -ForegroundColor Cyan

        # NTP Configuration
        $ntpOutput = Invoke-Command -ComputerName $dc.HostName -ScriptBlock {
            w32tm /query /status 2>&1
        }

        # Parse NTP Info
        $ntpSource = ($ntpOutput | Where-Object { $_ -match "Source:" }) -replace "Source:\s+",""
        $lastSync = ($ntpOutput | Where-Object { $_ -match "Last Successful Sync Time:" }) -replace "Last Successful Sync Time:\s+",""
        $stratum = ($ntpOutput | Where-Object { $_ -match "Stratum:" }) -replace "Stratum:\s+",""

        # FSMO Role Check
        $isPDC = if ($dc.OperationMasterRoles -contains "PDCEmulator") { "PDC Emulator" } else { "-" }

        # Type Check
        $typeOutput = Invoke-Command -ComputerName $dc.HostName -ScriptBlock {
            (w32tm /query /configuration | Select-String "Type").ToString()
        }
        $ntpType = ($typeOutput -split ':')[-1].Trim()

        # Add to Report
        $ntpReport += [PSCustomObject]@{
            'Domain'                 = $dc.Domain
            'Domain Controller'       = $dc.HostName
            'FSMO'                    = $isPDC
            'NTP Source'              = $ntpSource
            'Last Successful Sync Time'= $lastSync
            'Stratum'                 = $stratum
            'Type'                    = $ntpType
        }
    }
    catch {
        Write-Warning "Error connecting to ${dc.HostName}: $($_.Exception.Message)"
    }
}

# ==============================
# HTML OUTPUT
# ==============================

$date = Get-Date -Format "yyyy-MM-dd HH:mm"

$html = @"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Domain Controllers NTP Report</title>
    <style>
        body {font-family: Arial; background-color: #f4f4f4; color: #333; padding: 20px;}
        .container {max-width: 1200px; margin: auto; background-color: white; padding: 30px;
            border-radius: 10px; box-shadow: 0 0 15px rgba(0,0,0,0.2);}
        h1 {text-align: center; color: #0078D7;}
        p {text-align: center; color: #555;}
        table {width: 100%; border-collapse: collapse; margin-top: 20px;}
        th {background-color: #002147; color: white; padding: 12px;}
        td {background-color: #f9f9f9; padding: 12px; border-bottom: 1px solid #ddd;}
    </style>
</head>
<body>
    <div class="container">
        <h1>Domain Controllers NTP Report</h1>
        <p>Generated on $date</p>
        <table>
            <tr>
                <th>Domain</th>
                <th>Domain Controller</th>
                <th>FSMO</th>
                <th>NTP Source</th>
                <th>Last Successful Sync Time</th>
                <th>Stratum</th>
                <th>Type</th>
            </tr>
"@

foreach ($entry in $ntpReport) {
    $html += "<tr>
        <td>$($entry.'Domain')</td>
        <td>$($entry.'Domain Controller')</td>
        <td>$($entry.'FSMO')</td>
        <td>$($entry.'NTP Source')</td>
        <td>$($entry.'Last Successful Sync Time')</td>
        <td>$($entry.'Stratum')</td>
        <td>$($entry.'Type')</td>
    </tr>"
}

$html += @"
        </table>
    </div>
</body>
</html>
"@

# Save report
$path = "C:\NTP_Health_Report.html"
$html | Out-File -FilePath $path -Encoding utf8

Write-Host "NTP HTML report has been generated: $path" -ForegroundColor Cyan
Start-Process $path

Leave a Reply

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

Back To Top