Skip to content

CheckSecurity

CheckSecurity checks host security posture: certificate expiry and (on Windows) the firewall profile state.

Enable module

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

[/modules]
CheckSecurity = enabled

Queries

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

List of commands:

A list of all available queries (check commands)

Command Description
check_activation Check the Windows activation/licensing state: license status, remaining grace or KMS renewal period and genuineness. Windows only.
check_antivirus Check registered antivirus products’ enabled/up-to-date state (Windows Security Center). Windows only.
check_bitlocker Check BitLocker drive-encryption protection status per volume. Windows only.
check_certificate Check X.509 certificate expiry/validity/hygiene from files (all platforms) or the Windows certificate store.
check_defender Check Microsoft Defender status: signature/scan age, real-time and tamper protection, engine/signature versions. Windows only.
check_file_security Check the owner and DACL of files, folders or service binaries; alerts on world-writable paths and unexpected owners. Windows only.
check_firewall Check the Windows firewall profile (Domain/Private/Public) enabled state. Windows only.
check_firewall_rules Check individual Windows firewall rules: assert that specific rules exist and are enabled, and find inbound allow rules that restrict neither address nor port. Windows only.
check_group_members Check local group membership (default Administrators) and alert on members not on an expected allow-list. Windows only.
check_local_accounts Check local user account hygiene: enabled/disabled, locked, password-required/expires, built-in admin/guest. Windows only.
check_nla Check the Network Location Awareness profile (public/private/domain) per network. Windows only.
check_secureboot Check whether UEFI Secure Boot is enabled. Windows only.
check_users Check the count and detail of logged-on / RDP sessions (Windows and Linux).

check_activation

Available on Windows only.

Check the Windows activation/licensing state: license status, remaining grace or KMS renewal period and genuineness. Windows only.

About check_activation

check_activation reports the Windows activation and licensing state: whether the installed product is licensed, how much of a grace or KMS renewal period is left and whether Windows considers itself genuine. An expiring grace period is worth knowing about before it ends — Windows starts nagging users, then blocks personalisation and eventually restricts functionality.

The data comes from SoftwareLicensingProduct (WMI, root\CIMV2), limited to products that have a product key installed. The genuine state is taken from the same class where it is exposed and otherwise from SLIsGenuineLocal in slc.dll; both are local calls that do not contact Microsoft.

By default only Windows itself is reported. all-products=true adds every other licensed product with an installed key (Office, for instance).

The activation_status keyword renders the licensing status as a word (the raw number is available as license_status). The old name status still works as a deprecated alias, but clashes with the generic status summary keyword.

Options:

Option Default Meaning
all-products false Report every licensed product with an installed key, not only Windows.
skip-genuine false Do not evaluate the genuine state; genuine_state then reads unknown.

Default thresholds: critical when licensed = 0 — that covers an unlicensed machine as well as one running on a grace period or already in the notification (“activate Windows”) state — and warning when grace_days > 0 and grace_days < 30. A permanently activated machine reports grace_days = 0, so the warning only fires where a countdown is actually running: the out-of-box grace period, or a KMS client that has not managed to renew. Note that a KMS client normally shows a large grace_days value (up to 180) even though it is perfectly healthy.

Only one row is expected, so the default perfdata label is the fixed word license; pass perf-syntax=${name} (or ${key}) to tell several products apart when using all-products=true. Windows only.

Jump to section:

Sample Commands

Check that Windows is activated (Windows)

The default is critical when Windows is not licensed and warning when a grace or KMS renewal period has less than 30 days left.

check_activation
L        cli OK: Windows(R), Professional edition: licensed (genuine, grace 0d)|'license_grace'=0d;0;0
check_activation
L        cli CRITICAL: Windows(R), Professional edition: initial_grace (genuine, grace 12d)|'license_grace'=12d;0;0

Show the channel, genuine state and remaining grace period

check_activation "top-syntax=${status}: ${list}" "detail-syntax=${name} [${channel}] status=${activation_status} genuine=${genuine_state} grace=${grace_days}d"
L        cli OK: Windows(R), Professional edition [Volume:GVLK] status=licensed genuine=genuine grace=178d|'license_grace'=178d;0;0

Warn earlier on a KMS client whose renewal is falling behind

A KMS activation is good for 180 days and is renewed every 7 days, so a countdown that gets far down means renewal has been failing for months.

check_activation "warning=grace_days > 0 and grace_days < 90"
L        cli WARNING: Windows(R), Professional edition: licensed (genuine, grace 61d)|'license_grace'=61d;0;0

Include every licensed product, not just Windows

Give each product its own perfdata label when you do.

check_activation all-products=true "detail-syntax=${name}: ${activation_status}" "perf-syntax=${key}"
L        cli OK: Windows(R), Professional edition: licensed, Office 16, Office16ProPlus edition: licensed|'W269N_grace'=0d;0;0 '6MWKP_grace'=0d;0;0

Alert only when Windows reports itself as non-genuine

genuine_state is unknown when the state could not be determined, so exclude it to avoid alerting on a missing answer.

check_activation "critical=genuine = 0 and genuine_state != 'unknown'"
L        cli CRITICAL: Windows(R), Professional edition: notification (invalid_license, grace 0d)|'license_grace'=0d;0;0

Skip the genuine evaluation

check_activation skip-genuine=true
L        cli OK: Windows(R), Professional edition: licensed (unknown, grace 0d)|'license_grace'=0d;0;0

On non-Windows platforms

check_activation
L        cli UNKNOWN: check_activation is not supported on this platform (Windows Software Licensing only)

Command-line Arguments

Option Default Value Description
all-products false Report every licensed product with an installed key (Office, …) instead of only Windows itself.
skip-genuine false Do not evaluate the genuine state (skips the SLIsGenuineLocal call); genuine_state then reads ‘unknown’.
all-products:

Report every licensed product with an installed key (Office, …) instead of only Windows itself.

Default Value: false

skip-genuine:

Do not evaluate the genuine state (skips the SLIsGenuineLocal call); genuine_state then reads ‘unknown’.

Default Value: false

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 grace_days > 0 and grace_days < 30
warn
critical licensed = 0
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax %(status): ${list}
empty-syntax %(status): No licensing information found (Software Licensing service unavailable?)
detail-syntax ${name}: ${activation_status} (${genuine_state}, grace ${grace_days}d)
perf-syntax license
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
activation_status Licensing status as a word: licensed, unlicensed, initial_grace, additional_grace, non_genuine_grace, notification, extended_grace
channel Product key channel: Retail, Volume:MAK, Volume:GVLK, OEM, …
description Product description including the licensing channel
genuine True when Windows reports itself as genuine (false also when it could not be determined)
genuine_state Genuine status as a word: genuine, invalid_license, tampered, offline, unknown
grace_days Remaining grace/renewal period in whole days (0 when no grace period applies)
grace_minutes Remaining grace/renewal period in minutes, as Windows reports it (0 when no grace period applies)
id Product SKU id (GUID)
is_windows True when the product is Windows itself (as opposed to another licensed product)
key Partial product key (the last five characters of the installed key)
license_status Raw LicenseStatus: 0 unlicensed, 1 licensed, 2 initial grace, 3 additional grace, 4 non-genuine grace, 5 notification, 6 extended grace
license_status_reason Raw LicenseStatusReason code explaining the status
licensed True when the product is fully licensed (activated)
name Product name, e.g. ‘Windows(R), Professional edition’

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_antivirus

Available on Windows only.

Check registered antivirus products’ enabled/up-to-date state (Windows Security Center). Windows only.

About check_antivirus

check_antivirus reports the antivirus products registered with the Windows Security Center (WMI root\SecurityCenter2 AntiVirusProduct), including third-party AV and Windows Defender. This is distinct from check_os_updates (which counts pending OS/Defender updates) — this check answers “is AV actually running and current.”

enabled/up_to_date are decoded from productState using the well-known heuristic (the 0x1000 bit = real-time protection on, the 0x10 bit = stale definitions); the raw value is exposed as product_state for auditing. Default threshold: critical if any product has enabled = 0 or up_to_date = 0. Windows only.

Jump to section:

Sample Commands

Check that antivirus is enabled and up to date (Windows)

The default is critical if any registered product has real-time protection off or stale definitions.

check_antivirus
L        cli OK: 1 antivirus product(s) healthy
check_antivirus
L        cli CRITICAL: Windows Defender (enabled=1 up_to_date=0)

Only require definitions to be current

check_antivirus "crit=up_to_date = 0"
L        cli OK: 1 antivirus product(s) healthy

Show each product’s state

check_antivirus "top-syntax=${list}" "detail-syntax=${name}: enabled=${enabled} current=${up_to_date} state=${product_state}"
L        cli OK: Windows Defender: enabled=1 current=1 state=397568

On non-Windows platforms

check_antivirus
L        cli UNKNOWN: check_antivirus is not supported on this platform (Windows Security Center only)

Command-line Arguments

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 enabled = 0 or up_to_date = 0
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax ${status}: ${count} antivirus product(s) healthy
empty-syntax No antivirus product registered
detail-syntax ${name} (enabled=${enabled} up_to_date=${up_to_date})
perf-syntax ${name}
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
enabled True if real-time protection is enabled
name Antivirus product display name
product_state Raw Security Center productState bitfield
up_to_date True if virus definitions are current

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_bitlocker

Available on Windows only.

Check BitLocker drive-encryption protection status per volume. Windows only.

About check_bitlocker

check_bitlocker reports the BitLocker protection state of each encryptable volume (WMI Win32_EncryptableVolume in root\CIMV2\Security\MicrosoftVolumeEncryption). Use it to confirm disk encryption is actually on where policy requires it.

Default threshold: critical if any volume has protected = 0. Filter to the volumes you care about (e.g. filter=drive = 'C:') to avoid alerting on recovery/utility partitions. Windows only. Reading this class requires elevation, so the agent service must run with sufficient privilege.

Jump to section:

Sample Commands

Check that all volumes are BitLocker-protected (Windows)

The default is critical if any encryptable volume is not protected.

check_bitlocker
L        cli OK: all 2 volume(s) protected
check_bitlocker
L        cli CRITICAL: D: protected=0

Only require the system drive to be protected

check_bitlocker "filter=drive = 'C:'" "crit=protected = 0"
L        cli OK: all 1 volume(s) protected

Show each volume’s protection state

check_bitlocker "top-syntax=${list}" "detail-syntax=${drive} protected=${protected} status=${protection_status}"
L        cli OK: C: protected=1 status=1, D: protected=1 status=1

On non-Windows platforms

check_bitlocker
L        cli UNKNOWN: check_bitlocker is not supported on this platform (Windows BitLocker only)

Command-line Arguments

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 protected = 0
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax ${status}: all ${count} volume(s) protected
empty-syntax No encryptable volumes found
detail-syntax ${drive} protected=${protected}
perf-syntax ${drive}
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
conversion_status Raw conversion status (0 decrypted, 1 encrypted, …)
drive Drive letter of the volume (may be empty for non-lettered volumes)
protected True if BitLocker protection is on (protection_status is 1)
protection_status Raw protection status (0 off, 1 on, 2 unknown)

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_certificate

Check X.509 certificate expiry/validity/hygiene from files (all platforms) or the Windows certificate store.

About check_certificate

check_certificate inspects X.509 certificates at rest and alerts on expiry, validity and TLS hygiene (weak keys/signatures, trust). It reads certificates from:

  • Files on disk (file=/path=) — PEM (including multi-certificate bundles), DER, and PKCS#12 (.pfx/.p12, with password=). A directory is scanned (add recursive=true to descend). This works on all platforms (parsing is OpenSSL-based).
  • The Windows certificate store (store=, e.g. My, Root, CA) at a location= of LocalMachine (default) or CurrentUser. Windows only — on other platforms store= returns a clear “not supported” message.

This is distinct from check_http’s ssl_expiry_days, which checks the certificate a live TLS endpoint serves. Use check_http for “is my website’s cert expiring”; use check_certificate for certificates in the store or on disk that are not served over HTTP (code-signing, RDP, client-auth, service certs, CA certs, or files a service loads at start-up).

Default thresholds: warn when expires_in < 30 days, critical when expires_in < 10 days.

Options: ca= supplies a CA bundle for the trusted check (defaults to the system trust store); password= unlocks a PKCS#12 file. When neither file= nor store= is given, or nothing matches, the check returns UNKNOWN rather than a silent OK.

Trust caveat: trusted requires the issuing chain to be resolvable — either present in the same file/batch (e.g. a full-chain PEM or a .pfx that bundles its CA) or reachable from the ca=/system store. A lone leaf whose intermediates are absent will read as trusted=0. Chain time validity is not checked here by design; combine with expired.

Jump to section:

Sample Commands

Check a certificate file’s expiry (default thresholds)

The default thresholds warn when a certificate expires within 30 days and go critical within 10 days (matching common practice).

check_certificate file=/etc/ssl/certs/mysite.pem
L        cli OK: all 1 certificate(s) are ok

A certificate close to expiry trips the default critical

check_certificate file=/etc/ssl/certs/soon.pem
L        cli CRITICAL: /CN=soon.example.com expires in 5d (2026-07-09 19:16:12)

Custom thresholds and perfdata

expires_in is the number of whole days until expiry (negative once expired) and is emitted as perfdata (unit d).

check_certificate file=/etc/ssl/certs/mysite.pem warning=expires_in<900
L        cli  Performance data: '/CN=valid.example.com'=825d;900;10

Scan a directory of certificates

check_certificate file=/etc/ssl/certs recursive=true "detail-syntax=${subject}: ${expires_in}d"
L        cli OK: all 137 certificate(s) are ok

Alert only on already-expired certificates

check_certificate file=/etc/pki/tls/certs critical=expired=1
L        cli OK: all 4 certificate(s) are ok

Flag weak keys or signatures (TLS hygiene)

check_certificate file=/etc/ssl/certs/mysite.pem "crit=weak_signature = 1 or weak_key = 1"
L        cli CRITICAL: /CN=legacy.example.com expires in 40d (2026-08-14 00:00:00)

Show the crypto detail for an audit:

check_certificate file=/etc/ssl/certs/mysite.pem "top-syntax=${list}" "detail-syntax=${subject}: ${signature_algorithm}, ${key_type}/${key_size}"
L        cli OK: /CN=mysite.example.com: sha256WithRSAEncryption, RSA/2048

Verify the certificate is trusted

trusted checks that the chain resolves to a trusted CA (time validity is ignored — combine with expired). Point ca= at a bundle, or omit it to use the system trust store:

check_certificate file=/etc/nginx/fullchain.pem "crit=not trusted or expired = 1"
check_certificate file=/etc/ssl/leaf.pem ca=/etc/ssl/corp-ca.pem "crit=not trusted"

Read a PKCS#12 (.pfx) file

check_certificate file=/opt/app/keystore.pfx password=changeit "crit=expires_in < 14"
L        cli OK: all 1 certificate(s) are ok

Windows certificate store (Windows only)

On Windows, store= enumerates a system certificate store; location= selects LocalMachine (default) or CurrentUser.

check_certificate store=My location=LocalMachine
L        cli OK: all 6 certificate(s) are ok
check_certificate store=My "filter=subject like 'CN=*.example.com'" "crit=expires_in < 14"
L        cli WARNING: CN=web.example.com expires in 9d (2026-07-13 00:00:00)

On non-Windows platforms store= is rejected with a clear message:

check_certificate store=My
L        cli UNKNOWN: store= (certificate store) is only supported on Windows; use file= on this platform

Command-line Arguments

Option Default Value Description
file A certificate file (PEM or DER) or a directory of them. Can be given multiple times.
path Alias for file.
recursive false Recurse into directories given via file=/path=.
password Password for PKCS#12 (.pfx/.p12) files.
ca CA bundle to evaluate the ‘trusted’ keyword against (defaults to the system trust store).
store Windows certificate store to enumerate (e.g. My, Root, CA). Windows only.
location LocalMachine Windows store location: LocalMachine or CurrentUser. Windows only.
recursive:

Recurse into directories given via file=/path=.

Default Value: false

location:

Windows store location: LocalMachine or CurrentUser. Windows only.

Default Value: LocalMachine

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 expires_in < 30
warn
critical expires_in < 10
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${problem_list}
ok-syntax %(status): all %(count) certificate(s) are ok
empty-syntax No certificates found
detail-syntax ${subject} expires in ${expires_in}d (${valid_to})
perf-syntax ${subject}
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
expired True if the certificate has already expired
expires_in Whole days until the certificate expires (negative if already expired)
expires_in_days Alias for expires_in
expires_in_sec Seconds until the certificate expires (negative if already expired)
issuer Certificate issuer distinguished name
key_size Public key size in bits
key_type Public key type (RSA, EC, DSA, …)
not_after The not-after / expiry date
not_before The not-before date
not_yet_valid True if the certificate is not yet valid (not-before is in the future)
self_signed True if the certificate is self-signed
serial Certificate serial number (hex)
signature_algorithm Signature algorithm (e.g. sha256WithRSAEncryption)
source Where the certificate was read from (file path or store)
store The store/source type (file or a Windows store name)
subject Certificate subject (e.g. /CN=host.example.com)
thumbprint SHA-1 fingerprint (lower-case hex)
trusted True if the certificate chains to a trusted CA (system store or ca=; time validity is ignored — use expired/not_yet_valid for that)
valid_from Not-before date (UTC)
valid_to Not-after / expiry date (UTC)
weak_key True if the key is weak (RSA/DSA < 2048 bits, or EC < 256 bits)
weak_signature True if signed with a weak algorithm (MD5 or SHA-1)

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_defender

Available on Windows only.

Check Microsoft Defender status: signature/scan age, real-time and tamper protection, engine/signature versions. Windows only.

About check_defender

check_defender reports Microsoft Defender’s own health, read from MSFT_MpComputerStatus (WMI namespace root\Microsoft\Windows\Defender). Where check_antivirus reads Security Center’s coarse “any AV registered / enabled / up-to-date” bits for whatever product is installed, this exposes the Defender-specific depth operators actually threshold on the very common Defender-only estate: how old the definitions are, when the machine last scanned, and whether real-time and tamper protection are on.

All keywords are reported on a single aggregate row.

Defaults: WARNING when signature_age > 3, CRITICAL when enabled = 0 or realtime_enabled = 0 or signature_age > 7. A negative (unknown / never) age never trips a threshold, so full_scan_age / quick_scan_age are informational unless you add your own thresholds.

Not-the-active-AV contract: when a third-party antivirus has taken over, Defender’s status class is unavailable. The check then returns UNKNOWN with an explanatory message (via the empty state) rather than a hard error — so it is safe to deploy fleet-wide and only alerts where Defender is actually the protecting product.

Jump to section:

Sample Commands

Default check (healthy Defender):

check_defender
OK: Defender enabled=1 realtime=1 tamper=0 sig_age=0d sig=1.455.84.0 engine=1.1.26060.3008

Alert only on protection state, ignore signature age:

check_defender "warning=none" "critical=enabled = 0 or realtime_enabled = 0"
OK: Defender enabled=1 realtime=1 tamper=0 sig_age=0d sig=1.455.84.0 engine=1.1.26060.3008

Require tamper protection to be on:

check_defender "critical=tamper_protection = 0"
CRITICAL: Defender enabled=1 realtime=1 tamper=0 sig_age=0d sig=1.455.84.0 engine=1.1.26060.3008

Tighten the signature-age thresholds (warn at 1 day, critical at 3):

check_defender "warning=signature_age > 1" "critical=signature_age > 3"
WARNING: Defender enabled=1 realtime=1 tamper=1 sig_age=2d sig=1.455.60.0 engine=1.1.26060.3008

Also alert if no quick scan has run in the last week:

check_defender "warning=signature_age > 3 or quick_scan_age > 7"
OK: Defender enabled=1 realtime=1 tamper=1 sig_age=0d sig=1.455.84.0 engine=1.1.26060.3008

Custom output listing scan ages and versions:

check_defender "top-syntax=%(status): %(list)" "detail-syntax=sig=%(signature_age)d quick=%(quick_scan_age)d full=%(full_scan_age)d engine=%(engine_version)"
OK: sig=0d quick=6d full=-1d engine=1.1.26060.3008

Where a third-party antivirus is the active product (Defender status unavailable):

check_defender
UNKNOWN: Microsoft Defender status unavailable (not installed or another antivirus is active)

Over NRPE against a remote host:

check_nscp_client --host 192.168.56.103 --command check_defender --argument "warning=signature_age > 2"
OK: Defender enabled=1 realtime=1 tamper=1 sig_age=0d sig=1.455.84.0 engine=1.1.26060.3008

Command-line Arguments

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 signature_age > 3
warn
critical enabled = 0 or realtime_enabled = 0 or signature_age > 7
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax %(status): Microsoft Defender healthy (signature age ${signature_age}d)
empty-syntax %(status): Microsoft Defender status unavailable (not installed or another antivirus is active)
detail-syntax Defender enabled=${enabled} realtime=${realtime_enabled} tamper=${tamper_protection} sig_age=${signature_age}d sig=${signature_version} engine=${engine_version}
perf-syntax defender
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
enabled True if Defender antivirus/service is enabled
engine_version Defender anti-malware engine version
full_scan_age Days since the last full scan (-1 if never/unknown)
product_version Defender platform/product version
quick_scan_age Days since the last quick scan (-1 if never/unknown)
realtime_enabled True if real-time protection is on
signature_age Antivirus signature age in days (-1 if unknown)
signature_version Antivirus signature (definition) version
tamper_protection True if tamper protection is on

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_file_security

Available on Windows only.

Check the owner and DACL of files, folders or service binaries; alerts on world-writable paths and unexpected owners. Windows only.

About check_file_security

check_file_security inspects the owner and the access control list of files, folders and service binaries, and alerts when something can be written by someone who should not be able to: a world-writable data directory, a service binary whose owner has changed, a folder that inherits Everyone: Modify from its parent.

Owner and DACL are read with GetNamedSecurityInfo; the ACL is then walked entry by entry (GetAce) so that inherited entries are judged exactly like the ones set on the object itself — inheritance is how most of these problems arrive. Trustees are resolved with LookupAccountSid. With service= the image path is first read from the service control manager, so the check follows the binary the service actually runs.

A trustee counts as having write access when its allow entry carries any of FILE_WRITE_DATA, FILE_APPEND_DATA, DELETE, FILE_DELETE_CHILD, WRITE_DAC, WRITE_OWNER, GENERIC_WRITE or GENERIC_ALL. The harmless FILE_WRITE_EA/FILE_WRITE_ATTRIBUTES bits, which Windows hands out widely, do not count on their own. A deny entry covering the same bits cancels the grant.

These trustees are always allowed to write: NT AUTHORITY\SYSTEM, BUILTIN\Administrators, NT SERVICE\TrustedInstaller and CREATOR OWNER. Write access held by Everyone, Authenticated Users, BUILTIN\Users, BUILTIN\Guests, BUILTIN\Power Users or ANONYMOUS LOGON makes the path world writable; any other trustee outside the allow-list is simply unexpected. All matching is done on the SID first, so it works on a localized Windows where these groups have translated names.

Options:

Option Repeatable Meaning
path (or file) yes File or directory to inspect.
service yes Service whose binary is inspected.
expected-owner yes An acceptable owner, matched by SID, DOMAIN\name or bare name. When omitted the owner is only reported.
allow-write yes A trustee allowed to hold write access, in addition to the four always-allowed ones.

At least one path or service is required; without either the check reports UNKNOWN rather than a silent OK.

Default thresholds: critical when exists = 0 or readable = 0 or owner_expected = 0 or world_writable = 1 and warning when unexpected_write = 1. Reading a security descriptor requires the agent to have permission to do so, which is why an unreadable descriptor is treated as a finding instead of a pass. Windows only.

Jump to section:

Sample Commands

Check that a data directory is not world-writable (Windows)

The default is critical when the path is missing or unreadable, when its owner is not on the expected list or when an untrusted group can write it.

check_file_security "path=C:\Program Files\NSClient++"
L        cli OK: C:\Program Files\NSClient++: owner NT AUTHORITY\SYSTEM, no unexpected write access
check_file_security "path=C:\ProgramData\app-data"
L        cli CRITICAL: C:\ProgramData\app-data: world writable by Everyone

Check several paths at once

check_file_security "path=C:\Windows\System32" "path=C:\Windows"
L        cli OK: C:\Windows\System32: owner NT SERVICE\TrustedInstaller, no unexpected write access, C:\Windows: owner NT SERVICE\TrustedInstaller, no unexpected write access

The default top syntax lists every path. A top syntax without ${list} gives a summary instead — and while everything is fine the built-in OK summary is used:

check_file_security "path=C:\Windows\System32" "path=C:\Windows" "top-syntax=${status}: ${problem_count} of ${count} path(s) have a problem"
L        cli OK: all 2 path(s) have the expected owner and no unexpected write access
check_file_security "path=C:\Windows" "path=C:\ProgramData\app-data" "top-syntax=${status}: ${problem_count} of ${count} path(s) have a problem"
L        cli CRITICAL: 1 of 2 path(s) have a problem

Check the binary a service runs

The image path is read from the service configuration, so a service whose binary was replaced or moved is caught as well.

check_file_security service=EventLog "top-syntax=${status}: ${list}" "detail-syntax=${service} (${path}): ${state}"
L        cli OK: EventLog (C:\Windows\System32\svchost.exe): owner NT SERVICE\TrustedInstaller, no unexpected write access
check_file_security service=NoSuchService
L        cli CRITICAL: NoSuchService: Service not found: NoSuchService

Require a specific owner

check_file_security "path=C:\Windows\System32\spoolsv.exe" "expected-owner=NT SERVICE\TrustedInstaller"
L        cli OK: C:\Windows\System32\spoolsv.exe: owner NT SERVICE\TrustedInstaller, no unexpected write access
check_file_security "path=C:\Windows\System32\spoolsv.exe" "expected-owner=NT AUTHORITY\SYSTEM"
L        cli CRITICAL: C:\Windows\System32\spoolsv.exe: unexpected owner NT SERVICE\TrustedInstaller

Allow a trustee that is supposed to have write access

Allow-list entries are matched by SID, by DOMAIN\name or by the bare name. SIDs are the safe choice on a localized Windows, where Everyone and BUILTIN\Users carry translated names.

check_file_security "path=C:\ProgramData\app-data" "allow-write=DOMAIN\backup-svc" allow-write=S-1-1-0
L        cli OK: C:\ProgramData\app-data: owner BUILTIN\Administrators, no unexpected write access

Show the whole access control list

Deny entries are prefixed with ! and inherited entries with ~.

check_file_security "path=C:\ProgramData\app-data" "top-syntax=${status}: ${list}" "detail-syntax=${path}: ${state} [${dacl}]"
L        cli CRITICAL: C:\ProgramData\app-data: world writable by Everyone, WS01\bob [Everyone(RWXD), ~NT AUTHORITY\SYSTEM(F), ~BUILTIN\Administrators(F), ~WS01\bob(F)]

Report who can write without alerting

check_file_security "path=C:\Windows\System32" warning=none critical=none "top-syntax=${status}: ${list}" "detail-syntax=owner=${owner} writable=${writable} aces=${ace_count}"
L        cli OK: owner=NT SERVICE\TrustedInstaller writable=NT SERVICE\TrustedInstaller, NT AUTHORITY\SYSTEM, BUILTIN\Administrators, CREATOR OWNER aces=13

On non-Windows platforms

check_file_security "path=/etc/nsclient"
L        cli UNKNOWN: check_file_security is not supported on this platform (Windows security descriptors only)

Command-line Arguments

Option Default Value Description
path File or directory to inspect (repeatable).
file Alias for path (repeatable).
service Windows service whose binary is inspected (repeatable); the image path is read from the service configuration.
expected-owner An acceptable owner (repeatable), matched against the SID, ‘DOMAIN\name’ or the bare name. Any other owner is CRITICAL. When omitted the owner is only reported.
allow-write A trustee allowed to hold write access (repeatable), in addition to SYSTEM, Administrators, TrustedInstaller and CREATOR OWNER.

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 unexpected_write = 1
warn
critical exists = 0 or readable = 0 or owner_expected = 0 or world_writable = 1
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax %(status): all %(count) path(s) have the expected owner and no unexpected write access
empty-syntax %(status): No paths checked
detail-syntax ${path}: ${state}
perf-syntax ${path}
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
ace_count Number of explicit entries in the DACL
dacl The DACL rendered as ‘trustee(rights)’; deny entries are prefixed with ‘!’ and inherited ones with ‘~’; rights are F (full) or a subset of R (read), W (write), X (execute), D (delete), P (permissions)
error Why the security descriptor could not be read (empty when it could)
exists True when the path exists
is_dir True when the path is a directory
owner Owner as ‘DOMAIN\name’ (the SID when it cannot be resolved)
owner_expected True when the owner is on the expected-owner list (or no list was given)
owner_sid Owner SID
path The inspected file or directory
readable True when the security descriptor could be read
service Service the path was resolved from (empty for a path= entry)
state One-line verdict: missing, unreadable, unexpected owner, world writable or ok
unexpected The trustees with write access that are not allow-listed
unexpected_write True when a trustee outside the allow-list holds write access
world_writable True when Everyone, Users, Authenticated Users, Guests, Power Users or Anonymous Logon holds write access
writable Comma separated trustees holding write access

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_firewall

Available on Windows only.

Check the Windows firewall profile (Domain/Private/Public) enabled state. Windows only.

About check_firewall

check_firewall reports the effective state of the Windows firewall profiles (Domain, Private, Public) — what Windows actually enforces. It reads the local store through the INetFwPolicy2 COM interface (no WMI needed) and then overlays any Group Policy resultant values (the ones the policy engine writes under HKLM\SOFTWARE\Policies\Microsoft\WindowsFirewall): a setting enforced through group policy wins over the local setting, exactly as the firewall service applies it. Both the modern per-profile policy keys and the legacy StandardProfile key (written by the pre-Vista “Protect all network connections” ADMX policy, still honoured and applying to both Private and Public) are read; when both are present the modern values win as a whole. This matches Get-NetFirewallProfile -PolicyStore ActiveStore — note that plain Get-NetFirewallProfile (and INetFwPolicy2 alone) shows only the local, pre-policy configuration.

Each profile is reported as one row.

Default threshold: critical if any profile has enabled = 0.

active reflects which profile(s) Network Location Awareness currently applies (INetFwPolicy2::CurrentProfileTypes). More than one profile can be active when several networks are connected; with no connected network Windows reports the Public profile as active. Its main use is catching a machine silently dropping from Domain/Private to Public after a router/adapter change — firewall rules scoped to the domain or private profile stop applying and services start getting blocked. This is opt-in via a warn/crit expression (see the samples) since being on the public profile is perfectly normal for e.g. laptops.

This check is Windows only. It models Windows’ fixed three-profile firewall, which does not map onto Linux firewalls (firewalld zones, ufw, nftables/iptables default policies); on non-Windows platforms it returns UNKNOWN with a clear message rather than pretending to check something equivalent.

Jump to section:

Sample Commands

Check that all Windows firewall profiles are enabled (Windows only)

By default the check is critical if any of the three profiles (Domain, Private, Public) has its firewall disabled.

check_firewall
L        cli OK: all 3 firewall profile(s) enabled
check_firewall
L        cli CRITICAL: Public=0

Only require a specific profile to be enabled

check_firewall "filter=profile = 'Domain'" crit=enabled=0
L        cli OK: all 1 firewall profile(s) enabled

Warn when the machine is on the Public profile

Network Location Awareness can silently re-categorise a network to public after a router or connection change; rules scoped to the domain/private profiles then stop applying and services get blocked. Warn on that (opt-in — on e.g. laptops the public profile is normal):

check_firewall "warn=active = 1 and profile = 'Public'" "detail-syntax=${profile} profile is active"
L        cli WARNING: Public profile is active

The active flags are also available for display and perfdata:

check_firewall "detail-syntax=${profile}: enabled=${enabled} active=${active}" top-syntax=${list}
L        cli OK: Domain: enabled=1 active=0, Private: enabled=1 active=0, Public: enabled=1 active=1

Show the default inbound/outbound actions

check_firewall "detail-syntax=${profile}: enabled=${enabled} in=${inbound} out=${outbound}" top-syntax=${list}
L        cli OK: Domain: enabled=1 in=block out=allow, Private: enabled=1 in=block out=allow, Public: enabled=1 in=block out=allow

Show whether the settings are enforced through group policy

The reported state is always the effective one: when the firewall is configured through group policy (local or AD), the enforced values are shown and policy reads group policy for that profile; on an unmanaged machine it reads local:

check_firewall "detail-syntax=${profile}: ${enabled} (${policy})" "top-syntax=${status}: ${list}"
L        cli OK: Domain: 1 (local), Private: 1 (local), Public: 1 (local)

On non-Windows platforms

check_firewall models the Windows three-profile firewall and is not implemented on Linux (whose firewalld/ufw/nftables model differs):

check_firewall
L        cli UNKNOWN: check_firewall is not supported on this platform (Windows-only; the Linux firewall model differs)

Command-line Arguments

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 enabled = 0
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${problem_list}
ok-syntax %(status): all %(count) firewall profile(s) enabled
empty-syntax No firewall profiles found
detail-syntax ${profile}=${enabled}
perf-syntax ${profile}
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
active True if the profile is currently applied to a connected network (e.g. NLA re-categorising a network to public makes the Public profile active)
enabled True if the profile’s firewall is enabled
inbound Default inbound action (allow/block)
outbound Default outbound action (allow/block)
policy Where the profile’s settings come from; ‘group policy’ if any of the reported settings is enforced through group policy, otherwise ‘local’
profile Firewall profile name (Domain, Private or Public)

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_firewall_rules

Available on Windows only.

Check individual Windows firewall rules: assert that specific rules exist and are enabled, and find inbound allow rules that restrict neither address nor port. Windows only.

About check_firewall_rules

check_firewall_rules reports the Windows firewall rules — one row per rule — where check_firewall reports only whether each profile is switched on. It answers the two questions the profile check cannot: is the rule I depend on still there and enabled, and is there an inbound allow rule that restricts nothing.

Rules are read through INetFwPolicy2::Rules, the same store Get-NetFirewallRule uses, in a single pass across all profiles. No WMI needed.

Options:

Option Repeatable Meaning
expect yes A rule that must exist and be enabled, matched on the exact name, case insensitively.

Windows leaves a scope field empty where the firewall UI shows “Any”; the check normalises those to *, so local_ports = '*' matches every unrestricted rule rather than only some of them.

Asserting a rule exists. expect= fails whether the rule was deleted or merely switched off, and says which: “no rule with this name” versus “the rule exists but is disabled”. Windows allows several rules to share a name (commonly one per profile); one enabled copy satisfies the expectation, which is how the firewall itself behaves. Rule names are localized — on a Swedish machine the RDP rule is Fjärrskrivbord - användarläge (TCP-In) — so take the names from the machine you are checking rather than from an English reference.

The any-any rule. any_any is deliberately restricted to inbound allow rules: outbound traffic is unrestricted by default on Windows, and a wide block is the opposite of a finding. It is offered as a keyword, not imposed as a threshold, because a normal Windows client legitimately has a hundred of them (every packaged app gets one) — alerting by default would be noise. On a curated server rule set, filter=any_any = 1 with a count threshold is a good bound.

Default thresholds: critical when present = 0, which only fires when expect= is used; nothing else alerts on its own. The default top syntax lists only the problem rules, because a normal host has several hundred rules and listing them all would be unreadable; count perfdata carries how many rules matched the filter. empty-state is OK. Windows only.

Jump to section:

Sample Commands

Check that the rules you depend on are in effect (Windows)

Without expect= the check just inventories the rule set; the default critical only fires for an expected rule that is not in effect.

check_firewall_rules
L        cli OK: 631 rule(s) checked, all as expected|'count'=631;0;0
check_firewall_rules "expect=Remote Desktop - User Mode (TCP-In)"
L        cli OK: 631 rule(s) checked, all as expected|'count'=631;0;0

A rule that was deleted and one that was merely switched off both fail, with different wording so you know which fix is needed:

check_firewall_rules "expect=NSCP no such rule zzz" "expect=Distributed Transaction Coordinator (TCP-in)"
L        cli CRITICAL: NSCP no such rule zzz: not in effect: no rule with this name, Distributed Transaction Coordinator (TCP-in): not in effect: the rule exists but is disabled|'count'=633;0;0

Rule names are localized: on a Swedish machine the RDP rule above is Fjärrskrivbord - användarläge (TCP-In). Take the names from the machine you are checking (Get-NetFirewallRule | Select DisplayName), or match on group instead.

Find inbound allow rules that restrict neither address nor port

any_any is offered as a keyword rather than a default threshold — a normal Windows client has a hundred of them (every packaged app rule), so alerting on them out of the box would be pure noise. On a server, where the rule set is curated, it is a useful thing to bound.

check_firewall_rules "filter=any_any = 1" "top-syntax=${count} unrestricted inbound allow rule(s)" "ok-syntax=${count} unrestricted inbound allow rule(s)"
L        cli 120 unrestricted inbound allow rule(s)|'count'=120;0;0

To bound how many there may be, threshold on count — and give the check a summary top syntax while you are at it, or the alert will list every rule that matched the filter:

check_firewall_rules "filter=any_any = 1" "warning=count > 5" "top-syntax=${status}: ${count} unrestricted inbound allow rule(s)"
L        cli WARNING: 120 unrestricted inbound allow rule(s)|'count'=120;5;0

Alert on any inbound allow rule that reaches a sensitive port

check_firewall_rules "critical=enabled = 1 and direction = 'in' and action = 'allow' and local_ports like '3389'"
L        cli CRITICAL: Open RDP to the world: in allow tcp port 3389 (unrestricted), all

Inventory what a rule actually does

An unrestricted address or port field reads *, matching what the firewall UI shows as “Any”.

check_firewall_rules "filter=name = 'File and Printer Sharing (SMB-In)'" "top-syntax=${list}" "ok-syntax=${list}" "detail-syntax=${name}: ${direction}/${action} proto=${protocol} lports=${local_ports} remote=${remote_addresses} profiles=${profiles}"
L        cli File and Printer Sharing (SMB-In): in/allow proto=tcp lports=445 remote=* profiles=domain,private

Count only what is switched on

check_firewall_rules "filter=enabled = 1" "top-syntax=${count} enabled rules" "ok-syntax=${count} enabled rules"
L        cli 416 enabled rules|'count'=416;0;0

On non-Windows platforms

check_firewall_rules
L        cli UNKNOWN: check_firewall_rules is not supported on this platform (Windows firewall rules only)

Command-line Arguments

Option Default Value Description
expect A rule that must exist and be enabled (repeatable), matched on the exact rule name, case insensitively. The check is CRITICAL when no enabled rule answers for the name - whether it was deleted or merely switched off. Rule names are localized, so take them from the machine you are checking.

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 present = 0
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): %(count) rule(s) checked, all as expected
empty-syntax %(status): No firewall rules matched
detail-syntax ${name}: ${state}
perf-syntax ${name}
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
action What the rule does with matching traffic: allow or block
any_any True for an enabled inbound allow rule that restricts neither the remote address nor the local port
any_port True when the rule covers any local port
any_remote True when the rule accepts traffic from any remote address
application Program the rule is bound to (empty when it is not program specific)
description Rule description
direction Direction the rule applies to: in or out
edge_traversal True when the rule accepts traffic that has traversed a NAT device
enabled True when the rule is switched on
expected True when the rule matched one of the expect= names
group Rule group, e.g. ‘Remote Desktop’; often a resource reference like ‘@FirewallAPI.dll,-28752’ for built-in rules
local_addresses Local addresses the rule covers (‘*’ for any)
local_ports Local ports the rule covers (‘*’ for any)
name Rule name as it appears in the firewall (localized on a localized Windows)
present True for a real rule; false for an expect= name that no enabled rule satisfies (that is the default critical)
profiles Profiles the rule applies to: all, or a comma separated subset of domain, private and public
protocol Protocol: tcp, udp, icmpv4, icmpv6, any, or the raw protocol number (e.g. 41 for IPv6)
remote_addresses Remote addresses the rule accepts traffic from (‘*’ for any)
remote_ports Remote ports the rule covers (‘*’ for any)
service Service the rule is bound to (empty when it is not service specific)
state One line summary of what the rule does, or why an expected rule is not in effect

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_group_members

Available on Windows only.

Check local group membership (default Administrators) and alert on members not on an expected allow-list. Windows only.

About check_group_members

check_group_members reports the membership of a local group (default Administrators) via NetLocalGroupGetMembers, and — given an expected allow-list — alerts on membership drift: any member that is not on the list. This is the standard “who is in the local Administrators group, and did that change?” check.

The check reports one row per member.

Options:

Option Description
group Local group to inspect (default Administrators)
expected An allowed member (repeatable), matched against DOMAIN\name or the bare name

Default: CRITICAL on drift (expected = 0). When no expected= list is given, every member is treated as expected, so the check simply lists the group’s members and is OK. empty-state is OK; a group that does not exist is reported as an error.

expected= entries match case-insensitively against either the full DOMAIN\name (e.g. BUILTIN\Administrators, MYPC\localadmin) or just the name (Administrator, Domain Admins).

Jump to section:

Sample Commands

List the local Administrators group (no allow-list → just enumerate):

check_group_members
OK: MYPC\Administrator (user), MYPC\localadmin (user), PRICER\Domain Admins (group)

Alert if the Administrators group contains anyone unexpected (drift detection):

check_group_members expected=Administrator "expected=Domain Admins" expected=localadmin
OK: All 3 member(s) are on the expected list.

Drift detected — an unexpected member is present:

check_group_members expected=Administrator "expected=Domain Admins"
CRITICAL: MYPC\intern (user)

Check a different group:

check_group_members group="Remote Desktop Users" expected=helpdesk
OK: All 1 member(s) are on the expected list.

Alert if a group should have no direct user members (only groups):

check_group_members group=Administrators "crit=type = 'user'"
OK: All 2 member(s) are on the expected list.

List members with their type and SID:

check_group_members "top-syntax=%(status): %(list)" "detail-syntax=%(member) [%(type)] %(sid)"
OK: MYPC\Administrator [user] S-1-5-21-...-500, PRICER\Domain Admins [group] S-1-5-21-...-512

A group that does not exist is reported as an error:

check_group_members group=NoSuchGroup
UNKNOWN: Local group not found: NoSuchGroup

Over NRPE:

check_nscp_client --host 192.168.56.103 --command check_group_members --argument "expected=Administrator" --argument "expected=Domain Admins"
OK: All 2 member(s) are on the expected list.

Command-line Arguments

Option Default Value Description
group Local group to inspect (default: Administrators)
expected An allowed member (repeatable), matched against ‘DOMAIN\name’ or the bare name. Any member NOT on this list is CRITICAL. When omitted, all members are listed instead.

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 expected = 0
crit
ok
debug false
show-all false
empty-state ok
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax %(status): All %(count) member(s) are on the expected list.
empty-syntax %(status): Group is empty
detail-syntax ${member} (${type})
perf-syntax ${member}
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
domain Member domain component (BUILTIN, machine, AD domain, …)
expected True if the member is on the expected= allow-list (or no list was given)
group The local group being checked
member Member as ‘DOMAIN\name’
name Member name component
sid Member SID
type Member type: user, group, wellknown, alias, deleted, unknown

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_local_accounts

Available on Windows only.

Check local user account hygiene: enabled/disabled, locked, password-required/expires, built-in admin/guest. Windows only.

About check_local_accounts

check_local_accounts reports local user account hygiene — the findings security baselines care about — from Win32_UserAccount (LocalAccount=TRUE). It produces one row per local account so you can express your own policy with filter expressions.

Defaults: WARNING if the built-in Guest account is enabled (enabled = 1 and is_builtin_guest = 1), CRITICAL if an enabled account requires no password (enabled = 1 and password_required = 0). Both are low-false-positive on a hardened host. empty-state is OK.

Build stricter policies from the keywords, e.g. a password that never expires on an enabled account (enabled = 1 and password_expires = 0), the built-in Administrator being enabled (is_builtin_admin = 1 and enabled = 1), or locked-out accounts (locked = 1). LocalAccount=TRUE scopes the query to the local SAM, so domain accounts are never enumerated.

Jump to section:

Sample Commands

Default hygiene check:

check_local_accounts
OK: All 5 local account(s) ok.

A finding — an enabled account with no password required (default CRITICAL):

check_local_accounts
CRITICAL: kiosk (enabled=1, pw_req=0, pw_exp=0, locked=0)

Alert if the built-in Administrator account is enabled (hardening baseline):

check_local_accounts "crit=is_builtin_admin = 1 and enabled = 1"
OK: All 5 local account(s) ok.

Alert on enabled accounts whose password never expires:

check_local_accounts "warn=enabled = 1 and password_expires = 0"
WARNING: svc_backup (enabled=1, pw_req=1, pw_exp=0, locked=0)

Report locked-out accounts:

check_local_accounts "filter=locked = 1" "warn=count > 0" "empty-state=ok"
OK: No local accounts found

List every local account with its flags:

check_local_accounts "warn=none" "crit=none" "top-syntax=%(status): %(list)" "detail-syntax=%(name) enabled=%(enabled) pw_req=%(password_required) pw_exp=%(password_expires)"
OK: Administrator enabled=0 pw_req=1 pw_exp=0, Guest enabled=0 pw_req=0 pw_exp=0, ...

Over NRPE:

check_nscp_client --host 192.168.56.103 --command check_local_accounts --argument "crit=enabled = 1 and password_required = 0"
OK: All 5 local account(s) ok.

Command-line Arguments

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 enabled = 1 and is_builtin_guest = 1
warn
critical enabled = 1 and password_required = 0
crit
ok
debug false
show-all false
empty-state ok
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax %(status): All %(count) local account(s) ok.
empty-syntax %(status): No local accounts found
detail-syntax ${name} (enabled=${enabled}, pw_req=${password_required}, pw_exp=${password_expires}, locked=${locked})
perf-syntax ${name}
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
disabled True if the account is disabled
enabled True if the account is enabled (convenience inverse of disabled)
is_builtin_admin True for the built-in Administrator account (RID 500)
is_builtin_guest True for the built-in Guest account (RID 501)
locked True if the account is locked out
name Account name
password_expires True if the password is set to expire
password_required True if a password is required to log on
sid Account SID

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_nla

Available on Windows only.

Check the Network Location Awareness profile (public/private/domain) per network. Windows only.

About check_nla

check_nla reports the Network Location Awareness profile of each network the machine knows about (the same classification Windows uses to pick a firewall profile), via the COM INetworkListManager interface. It is a security-posture check: confirm a domain-joined machine is on the domain category and not accidentally treating a network as private/public.

There is no default threshold — assert the expected posture, e.g. crit=connected = 1 and category != 'domain'. Windows only; on other platforms it returns UNKNOWN with a clear message (Linux has no equivalent network-profile concept).

Jump to section:

Sample Commands

Assert the active network is the domain profile (Windows)

check_nla reports each network’s Location Awareness category. There is no default threshold — assert the posture you expect:

check_nla "crit=connected = 1 and category != 'domain'" "detail-syntax=${network}=${category}"
L        cli OK: all networks ok

Alert if any connected network is classified Public

check_nla "crit=connected = 1 and category = 'public'"
L        cli CRITICAL: Wi-Fi=public

List every known network and its category

check_nla "top-syntax=${list}" "detail-syntax=${network}: ${category} (connected=${connected})"
L        cli OK: Corp.example.com: domain (connected=1), Café-WiFi: public (connected=0)

On non-Windows platforms

check_nla
L        cli UNKNOWN: check_nla is not supported on this platform (Windows Network Location Awareness only)

Command-line Arguments

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
crit
ok
debug false
show-all false
empty-state ok
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax ${status}: all networks ok
empty-syntax No networks found
detail-syntax ${network}=${category}
perf-syntax ${network}
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
category Network category: public, private or domain
connected True if the network is currently connected
network Network name

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_secureboot

Available on Windows only.

Check whether UEFI Secure Boot is enabled. Windows only.

About check_secureboot

check_secureboot reports whether UEFI Secure Boot is enabled, read from the registry value HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot\State\UEFISecureBootEnabled (the same source Confirm-SecureBootUEFI uses). It returns a single result.

Default threshold: critical if enabled = 0. On legacy-BIOS machines the value is absent, so both enabled and supported are 0 — use supported to tell “off” apart from “not applicable” on mixed fleets. Windows only.

Jump to section:

Sample Commands

Check that UEFI Secure Boot is enabled (Windows)

The default is critical if Secure Boot is not enabled.

check_secureboot
L        cli OK: secure boot is enabled
check_secureboot
L        cli CRITICAL: secure boot enabled=0 supported=1

Distinguish “disabled” from “not supported” (legacy BIOS)

supported is 0 when the platform does not expose a Secure Boot state (legacy BIOS boot). Treat that as WARNING rather than CRITICAL if you monitor mixed fleets:

check_secureboot "warn=supported = 0" "crit=supported = 1 and enabled = 0"
L        cli WARNING: secure boot enabled=0 supported=0

On non-Windows platforms

check_secureboot
L        cli UNKNOWN: check_secureboot is not supported on this platform (Windows/UEFI only)

Command-line Arguments

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 enabled = 0
crit
ok
debug false
show-all false
empty-state unknown
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${list}
ok-syntax ${status}: secure boot is enabled
empty-syntax No Secure Boot state
detail-syntax secure boot enabled=${enabled} supported=${supported}
perf-syntax secureboot
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
enabled True if UEFI Secure Boot is enabled
supported True if the platform reports a Secure Boot state (UEFI); false on legacy BIOS boots

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_users

Check the count and detail of logged-on / RDP sessions (Windows and Linux).

About check_users

check_users reports the interactive logon sessions on the host — count and per-session detail. It works on both platforms:

  • Windows — via the Remote Desktop Services (WTS) API, so it distinguishes console from RDP and active from disconnected sessions (no WMI needed).
  • Linux — via the utmp database (the same source as who); network logins (ssh) carry the remote host in client.

The built-in count summary variable holds the number of matching sessions.

There is no default threshold — this is a count/inventory check, so supply your own, e.g. crit=count > 10 or crit=session_state = 'disconnected'. Sessions with no user (services, the RDP listener) are not counted.

Jump to section:

Sample Commands

Count the logged-on users

check_users
L        cli OK: 2 user(s) logged on: mickem, root

Alert when too many sessions are open

count is a built-in summary variable.

check_users "warn=count > 5" "crit=count > 10"
L        cli OK: 2 user(s) logged on: mickem, root

Alert on any interactive session (e.g. a locked-down server)

check_users "crit=count > 0"
L        cli CRITICAL: 2 user(s) logged on: mickem, root

Only count RDP / remote sessions

check_users "filter=session_type = 'rdp'" "crit=count > 0"

On Linux, network logins (ssh) have session_type = 'remote':

check_users "filter=session_type = 'remote'" "detail-syntax=${user}@${client}" "top-syntax=${list}"
L        cli OK: [email protected]

Alert on a disconnected-but-open RDP session (Windows)

check_users "crit=session_state = 'disconnected'" "detail-syntax=${user} (${session_state})"

Command-line Arguments

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
crit
ok
debug false
show-all false
empty-state ok
perf-config
escape-html false
list-separator ,
top-syntax ${status}: ${count} user(s) logged on: ${list}
ok-syntax ${status}: ${count} user(s) logged on
empty-syntax No users logged on
detail-syntax ${user}
perf-syntax ${user}
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
client Client name (Windows) or remote host (Linux); empty for the local console
session_state Session state: active, disconnected, connected, … (Linux logins are always active)
session_type Session type: console, rdp, remote, ica, …
user The account name of the logged-on user

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.