Skip to content

CheckActiveDirectory

Available on Windows only.

Experimental

This module is experimental: it works, but its options, filter keywords and output may change in a future release. Please try it and report anything that does not behave the way you expect.

CheckActiveDirectory checks Active Directory health: replication on domain controllers, the machine-account secure channel and Kerberos KDC availability.

Enable module

To enable this module and allow using the commands you need to add CheckActiveDirectory = enabled to the [/modules] section in nsclient.ini:

[/modules]
CheckActiveDirectory = enabled

Queries

A quick reference for all available queries (check commands) in the CheckActiveDirectory module.

List of commands:

A list of all available queries (check commands)

Command Description
check_ad_replication (experimental) Check inbound Active Directory replication links on a domain controller (last success, consecutive failures). Windows only.
check_kdc (experimental) Check that Kerberos KDCs answer an AS-REQ probe on port 88 (a real Kerberos exchange, not just a port check). Windows only.
check_secure_channel (experimental) Verify the machine-account secure channel to the domain via netlogon. Windows only.

check_ad_replication

Check inbound Active Directory replication links on a domain controller (last success, consecutive failures). Windows only.

About check_ad_replication

check_ad_replication reads the inbound replication state of a domain controller straight from the directory service (DsReplicaGetInfo, the same source repadmin /showrepl uses). Each inbound replication link — a (naming context, source DC) pair — becomes one row: when it last attempted and last managed to sync, and how many attempts in a row have failed.

Replication failures are the classic silent AD killer: a DC that has not replicated for longer than the tombstone lifetime (typically 60–180 days) is permanently orphaned and must be rebuilt. This check alerts long before that.

Defaults: WARNING when consecutive_failures > 0, CRITICAL when consecutive_failures > 4 or last_success < -24h. A link that has never synced trips the 24-hour rule by design.

Options: server=<dc> checks another domain controller (default: the local machine — replication state is per-DC, so run the check on every DC). timeout=<ms> (default 5000) bounds the whole read, the local machine included.

Not-a-DC contract: on a host that is not a domain controller, the check returns UNKNOWN with a “Not a domain controller” message rather than a hard error, so it is safe to deploy fleet-wide. The machine role is what decides this (DsRoleGetPrimaryDomainInformation), not the bind failure itself: a real domain controller that fails to answer — stopped NTDS, access denied, RPC unavailable — is reported as a plain failure, because that is the outage this check exists to surface. A single-DC domain (no replication partners) returns OK with an explanatory empty-state message.

Timeout: none of the directory service calls take a timeout of their own, so the check runs the read on a worker thread and stops waiting for it when timeout= runs out, reporting UNKNOWN (“No answer from the directory service on dc02 within 5000ms”). That covers the case a port check misses: a firewall that lets the RPC endpoint mapper (TCP 135) through but drops the dynamic RPC port the directory service answers on, where the bind would otherwise block for as long as RPC keeps retrying. A remote server= is still probed on port 135 first, so a host that is down or blocked outright reports exactly that. Windows cannot cancel the blocked call, so the worker is left to finish on its own; until it has, further runs against the same server report that the previous read has not returned instead of starting another thread.

Jump to section:

Sample Commands

Default check (healthy domain controller):

check_ad_replication
OK: all 6 replication links are healthy|'DC02 DC=example,DC=com'=0;0;4 'DC02 CN=Configuration,DC=example,DC=com'=0;0;4 ...

A partner has been failing for a while:

check_ad_replication
CRITICAL: DC02 DC=example,DC=com: 7 failures, last success 2026-08-10 03:11:42|'DC02 DC=example,DC=com'=7;0;4 ...

Only alert on prolonged outages (ignore single hiccups):

check_ad_replication "warning=none" "critical=last_success < -24h"
OK: all 6 replication links are healthy

Check a remote domain controller:

check_ad_replication server=dc02.example.com
OK: all 6 replication links are healthy

Custom output listing every link and its last error:

check_ad_replication "top-syntax=${status}: ${list}" "detail-syntax=${source} -> ${naming_context}: ${last_error_message}"
WARNING: DC02 -> DC=example,DC=com: The RPC server is unavailable., DC03 -> DC=example,DC=com: 

On a host that is not a domain controller (the fleet-wide-safe contract):

check_ad_replication
Not a domain controller: Failed to bind to the directory service on WEB01: 6d9: There are no more endpoints available from the endpoint mapper.

On the only domain controller of a single-DC domain:

check_ad_replication
No replication partners found (single domain controller?)

Command-line Arguments

Option Default Value Description
server The domain controller to check (default: the local machine).
timeout 5000 Timeout in milliseconds for the whole read, the directory service bind included.
timeout:

Timeout in milliseconds for the whole read, the directory service bind included.

Default Value: 5000

Common options:

These options are shared by all filter based commands and are described on the common options page; the default values below are specific to this command.

Option Default Value
filter
warning consecutive_failures > 0
warn
critical consecutive_failures > 4 or last_success < -24h
crit
ok
debug false
show-all false
empty-state ok
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${problem_list}
ok-syntax %(status): all %(count) replication links are healthy
empty-syntax No replication partners found (single domain controller?)
detail-syntax ${source} ${naming_context}: ${consecutive_failures} failures, last success ${last_success}
perf-syntax ${source} ${naming_context}
byte-unit
decimal-separator
decimals -1
thousands-separator

This command also accepts the standard help options: help, help-pb, show-default, help-short.

Filter keywords

Option Description
consecutive_failures Number of consecutive failed sync attempts on this link
failed True when the last sync attempt failed
last_attempt When the last sync was attempted
last_error Win32 result code of the last sync attempt (0 = success)
last_error_message Human readable message for the last sync result (empty when ok)
last_success When the last sync succeeded (epoch 0 = never)
naming_context The replicated directory partition (naming context) DN
source The source domain controller this link replicates from
source_address Transport address of the source (GUID-based DNS name)
source_dsa Full DN of the source directory service agent

This command also supports the common filter keywords: count, total, ok_count, warn_count, crit_count, problem_count, list, ok_list, warn_list, crit_list, problem_list, detail_list, sep, status.

check_kdc

Check that Kerberos KDCs answer an AS-REQ probe on port 88 (a real Kerberos exchange, not just a port check). Windows only.

About check_kdc

check_kdc verifies that a Kerberos KDC is actually issuing responses — not just that port 88 is open. It sends a real (unauthenticated) AS-REQ over TCP and classifies the answer: an AS-REP or any KRB-ERROR proves a live KDC, while silence, a reset or a non-Kerberos answer means authentication is down even though a port probe would still pass. Kerberos failure looks like “everything is broken” to users, so this is the check to point at every domain controller.

Which account the probe names

The AS-REQ names an account that exists: by default this machine’s own (HOST$, the account Windows itself authenticates with), which is available whenever the probed realm is the domain the machine is joined to. The KDC answers it with KDC_ERR_PREAUTH_REQUIRED — the healthy result — because the probe never sends a password: it asks for a ticket, and the KDC asks it to prove who it is. No password is ever sent and nothing counts against the account’s lockout.

A probe for a name that does not exist would get KDC_ERR_C_PRINCIPAL_UNKNOWN instead. That still proves the KDC is alive, but the DC logs it as a failed ticket request (event 4768), and a monitor doing that against every DC every few minutes is exactly the pattern user-enumeration detections alert on. So the check never invents one: to probe a realm this machine has no account in (a foreign realm, or from a machine that is not domain-joined), name one with principal=. Pick an account that exists and requires Kerberos pre-authentication (every account does unless Do not require Kerberos preauthentication is set on it) and is enabled: a disabled or expired account is refused with its own logged failure. Without principal= the check returns UNKNOWN saying so, before anything is sent.

The principal keyword shows which account was named.

Thresholds and options

Defaults: WARNING when time > 1000, CRITICAL when responding = 0.

A host whose name does not resolve never starts an exchange, so it has no round-trip time to report: time renders as ? and contributes no perf data rather than putting a sentinel into the series. It still goes CRITICAL on responding = 0.

Options: server=<host> (repeatable) picks the KDC(s) to probe and realm=<REALM> the realm; both default to what the domain join discovers (DsGetDcName). A discovered realm is uppercased the way Active Directory reports it; an explicit realm= is sent exactly as typed, since Kerberos realms are case sensitive and a non-AD KDC may serve a lowercase one (max 255 characters). On a machine that is not domain-joined, server=, realm= and principal= are required and the check says so with UNKNOWN.

timeout=<ms> (default 5000) bounds the whole probe, name lookups included: all KDCs are looked up and probed concurrently under one deadline, so it also bounds the whole check when several KDCs are unreachable. A lookup the DNS server never answers is reported as resolve failed: no answer from DNS in time when the deadline passes; Windows cannot cancel it, so it finishes on its own in the background, and until it has, further runs against the same host report that the previous lookup has not returned rather than starting another.

Jump to section:

Sample Commands

Default check (domain-joined; probes the discovered KDC):

check_kdc
OK: dc01.example.com: KRB-ERROR KDC_ERR_PREAUTH_REQUIRED (2ms)|'dc01.example.com'=2ms;1000

KDC_ERR_PREAUTH_REQUIRED is the healthy answer: the probe named this machine’s own account, and the KDC processed the request and asked it to pre-authenticate.

Probe specific KDCs explicitly (works from any machine, no domain join needed):

check_kdc server=dc01.example.com server=dc02.example.com realm=EXAMPLE.COM principal=svc-monitor
OK: all 2 KDC(s) are responding|'dc01.example.com'=2ms;1000 'dc02.example.com'=3ms;1000

A realm this machine has no account in, without principal=:

check_kdc server=kdc.partner.test realm=PARTNER.TEST
principal= is required to probe PARTNER.TEST: this machine has no account in that realm. Name an account that exists there and requires pre-authentication.

KDC down (nothing answering on the port):

check_kdc server=dc01.example.com realm=EXAMPLE.COM principal=svc-monitor
CRITICAL: dc01.example.com: connect failed: No connection could be made because the target machine actively refused it (2028ms)|'dc01.example.com'=2028ms;1000

Something answered, but it does not speak Kerberos:

check_kdc server=dc01.example.com realm=EXAMPLE.COM principal=svc-monitor
CRITICAL: dc01.example.com: invalid response (5ms)|'dc01.example.com'=5ms;1000

Tighten the latency alert (Kerberos slowness precedes logon storms):

check_kdc "warning=time > 200" "critical=responding = 0 or time > 2000"
OK: dc01.example.com: KRB-ERROR KDC_ERR_PREAUTH_REQUIRED (2ms)|'dc01.example.com'=2ms;200;2000

Custom output with the raw error code:

check_kdc "detail-syntax=${kdc} port ${port} realm ${realm} as ${principal}: ${response} code=${error_code}"
OK: dc01.example.com port 88 realm EXAMPLE.COM as WS01$: KRB-ERROR KDC_ERR_PREAUTH_REQUIRED code=25

On a machine that is not domain-joined (no server= given):

check_kdc
Failed to locate a KDC (is this machine domain-joined?): 54b: The specified domain either does not exist or could not be contacted. Specify server=, realm= and principal=.

Command-line Arguments

Option Default Value Description
server KDC host to probe; can be given multiple times (default: the KDC located via the domain join).
realm Kerberos realm to request a ticket for (default: the joined domain; required when not domain-joined).
principal Client principal to name in the AS-REQ (default: this machine’s account, HOST$, when probing the domain it is joined to; required for any other realm). Name an account that exists and requires pre-authentication.
port 88 TCP port to probe.
timeout 5000 Timeout in milliseconds for the probes, name lookups included. All KDCs are probed concurrently, so this also bounds the whole check.
port:

TCP port to probe.

Default Value: 88

timeout:

Timeout in milliseconds for the probes, name lookups included. All KDCs are probed concurrently, so this also bounds the whole check.

Default Value: 5000

Common options:

These options are shared by all filter based commands and are described on the common options page; the default values below are specific to this command.

Option Default Value
filter
warning time > 1000
warn
critical responding = 0
crit
ok
debug false
show-all false
empty-state ignored
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax %(status): all %(count) KDC(s) are responding
empty-syntax
detail-syntax ${kdc}: ${response} (${time}ms)
perf-syntax ${kdc}
byte-unit
decimal-separator
decimals -1
thousands-separator

This command also accepts the standard help options: help, help-pb, show-default, help-short.

Filter keywords

Option Description
error_code KRB-ERROR code from the response (-1 when none)
kdc The KDC host that was probed
port TCP port probed
principal The client principal the probe named (this machine’s account unless principal= was given)
realm The Kerberos realm the probe requested a ticket for
responding True when the KDC answered the AS-REQ with a well-formed Kerberos message
response What the KDC answered (or the transport error)
time Probe round-trip time in milliseconds (none when the host never resolved)

This command also supports the common filter keywords: count, total, ok_count, warn_count, crit_count, problem_count, list, ok_list, warn_list, crit_list, problem_list, detail_list, sep, status.

check_secure_channel

Verify the machine-account secure channel to the domain via netlogon. Windows only.

About check_secure_channel

check_secure_channel verifies the machine-account secure channel — the authenticated netlogon session every domain member maintains to a domain controller. A broken secure channel (“the trust relationship between this workstation and the primary domain failed”) blocks every domain logon on the host while port- and service-level checks keep reporting green, which makes it one of the highest-signal single-bit checks a domain estate can run.

By default the check actively verifies the channel (netlogon TC_VERIFY, the same operation as nltest /sc_verify / Test-ComputerSecureChannel), which contacts the DC. Pass verify=false for a passive status query only.

Defaults: CRITICAL when healthy = 0; no warning threshold.

Options: domain=<name> checks the channel to a specific trusted domain (default: the domain the checked machine is joined to); server=<host> queries another computer’s netlogon service (its join state is then also read from that computer when domain= is not given).

Not-joined contract: on a workgroup or standalone machine the check returns UNKNOWN (“not joined to a domain”) rather than a hard error, so it is safe to deploy fleet-wide.

CRITICAL means a broken channel, nothing else: when the netlogon query itself fails — the service is stopped or restarting, the caller lacks administrator rights, or the RPC connection to server= fails — the check returns UNKNOWN with the failure message instead of scoring the channel as broken. Verifying the channel requires administrator rights on the target, which the NSClient++ service (LocalSystem) has; running the check as an unprivileged user yields that UNKNOWN.

Jump to section:

Sample Commands

Default check (healthy domain member; actively verifies the channel):

check_secure_channel
OK: secure channel to EXAMPLE via DC01.example.com: OK

Broken secure channel (machine-account password out of sync):

check_secure_channel
CRITICAL: secure channel to EXAMPLE via : The trust relationship between this workstation and the primary domain failed.

Passive status query only (do not contact the DC):

check_secure_channel verify=false
OK: secure channel to EXAMPLE via DC01.example.com: OK

Check the channel to a specific trusted domain:

check_secure_channel domain=PARTNER
OK: secure channel to PARTNER via DC05.partner.example: OK

Custom output with the raw status code:

check_secure_channel "detail-syntax=${domain}: dc=${dc} code=${error_code}"
OK: EXAMPLE: dc=DC01.example.com code=0

On a workgroup machine (the fleet-wide-safe contract):

check_secure_channel
This machine is not joined to a domain (workgroup WORKGROUP); there is no secure channel to check

Command-line Arguments

Option Default Value Description
domain The trusted domain to check the channel to (default: the domain this machine is joined to).
server The computer whose secure channel to check (default: the local machine).
verify true Actively verify the channel by contacting the DC (netlogon TC_VERIFY). Set verify=false for a passive status query only.
verify:

Actively verify the channel by contacting the DC (netlogon TC_VERIFY). Set verify=false for a passive status query only.

Default Value: true

Common options:

These options are shared by all filter based commands and are described on the common options page; the default values below are specific to this command.

Option Default Value
filter
warning
warn
critical healthy = 0
crit
ok
debug false
show-all false
empty-state ignored
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax
empty-syntax
detail-syntax secure channel to ${domain} via ${dc}: ${error_message}
perf-syntax ${domain}
byte-unit
decimal-separator
decimals -1
thousands-separator

This command also accepts the standard help options: help, help-pb, show-default, help-short.

Filter keywords

Option Description
dc The domain controller the secure channel is established with
domain The trusted domain the secure channel points at
error_code Win32 status of the secure channel (0 = healthy)
error_message Human readable channel state (OK or the failure message)
healthy True when the secure channel is established and verified

This command also supports the common filter keywords: count, total, ok_count, warn_count, crit_count, problem_count, list, ok_list, warn_list, crit_list, problem_list, detail_list, sep, status.