Domain Controller Baseline Monitoring Deployment with PowerShell

Overview

Maintaining performance visibility across all Domain Controllers is critical in any Active Directory environment.

This script:

  • Discovers all Domain Controllers automatically
  • Creates a Performance Monitor Data Collector Set remotely
  • Configures baseline counters
  • Starts continuous circular logging
  • Ensures required folder structure exists
  • Executes safely across all DCs
    It provides a standardized, automated method for collecting DC performance baselines.
Why Baseline Domain Controllers?
Without baseline metrics, it is impossible to determine:
  • Whether high CPU is abnormal
  • If LDAP traffic has increased unexpectedly
  • If disk latency is degrading replication
  • If memory pressure is affecting authentication
  • Whether network throughput is bottlenecked

Baselining allows comparison between:

  • Post-change performance
  • Normal operation
  • Incident periods
What the Script does

This script automates the deployment of a standardized performance baseline configuration across all Domain Controllers in the Active Directory environment. It dynamically discovers every domain controller, ensures a dedicated logging directory exists, remotely creates a Performance Monitor Data Collector Set using logman, and starts continuous circular logging. The collector captures critical system and Active Directory counters—including CPU usage, memory pressure, disk I/O, network throughput, and NTDS activity—at five-minute intervals, storing the data locally in a controlled, size-limited format. By executing these steps remotely via WMI, the script enforces consistent monitoring configuration across the infrastructure without requiring manual setup on each server, enabling long-term performance analysis, capacity planning, and incident investigation.

# Import AD module if not already loaded
Import-Module ActiveDirectory

# Get a list of Domain Controller hostnames
$DomainControllers = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName

# Commands to run remotely (broken into steps for reliability)
$logmanCreate = 'logman create counter DC_Baseline_Monitoring -c "\Processor(_Total)\% Processor Time" "\Memory\Available MBytes" "\Memory\Pages/sec" "\LogicalDisk(_Total)\% Free Space" "\PhysicalDisk(_Total)\Disk Reads/sec" "\PhysicalDisk(_Total)\Disk Writes/sec" "\Network Interface(*)\Bytes Total/sec" "\NTDS\LDAP Searches/sec" "\NTDS\DS Directory Reads/sec" "\NTDS\DS Directory Writes/sec" -si 00:05:00 -o "C:\PerfLogs\DC_Baseline\DC_Baseline_Monitoring" -f bincirc -max 500 -v mmddhhmm -cnf 01:00:00'
$logmanStart = 'logman start DC_Baseline_Monitoring'

# Prepare the log directory creation as a PowerShell command
$prepareFolder = 'if (!(Test-Path C:\PerfLogs\DC_Baseline)) { New-Item -ItemType Directory -Path C:\PerfLogs\DC_Baseline }'

foreach ($dc in $DomainControllers) {
    Write-Host "Configuring $dc..." -ForegroundColor Cyan
    try {
        # 1. Make sure the folder structure exists
        $cmd = "powershell.exe -Command `$ErrorActionPreference = 'SilentlyContinue'; $prepareFolder"
        $wmi = [WMIClass]"\\$dc\root\cimv2:Win32_Process"
        $result = $wmi.Create($cmd)
        if ($result.ReturnValue -eq 0) {
            Write-Host "Log folder checked/created on $dc."
        } else {
            Write-Warning "Failed to create log folder on $dc. ReturnValue: $($result.ReturnValue)"
        }

        # 2. Create the Data Collector Set (safe to rerun; will fail if exists)
        $result = $wmi.Create($logmanCreate)
        if ($result.ReturnValue -eq 0) {
            Write-Host "Data Collector Set created on $dc."
        } else {
            Write-Warning "Data Collector Set may already exist on $dc (ReturnValue: $($result.ReturnValue))."
        }

        # 3. Start the Data Collector Set
        $result = $wmi.Create($logmanStart)
        if ($result.ReturnValue -eq 0) {
            Write-Host "Data Collector Set started on $dc."
        } else {
            Write-Warning "Data Collector Set may already be running on $dc (ReturnValue: $($result.ReturnValue))."
        }
    } catch {
        Write-Error "Error contacting $dc: $_"
    }
}
K Shankar R Karanth
K Shankar R Karanth
Articles: 8