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, withpassword=). A directory is scanned (addrecursive=trueto descend). This works on all platforms (parsing is OpenSSL-based). - The Windows certificate store (
store=, e.g.My,Root,CA) at alocation=ofLocalMachine(default) orCurrentUser. Windows only — on other platformsstore=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:
trustedrequires the issuing chain to be resolvable — either present in the same file/batch (e.g. a full-chain PEM or a.pfxthat bundles its CA) or reachable from theca=/system store. A lone leaf whose intermediates are absent will read astrusted=0. Chain time validity is not checked here by design; combine withexpired.
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 inclient.
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.