Skip to content

Commit df0d10d

Browse files
committed
fix(by-winrm): apply --severity-timeout/--severity-stderr, improve docs
- Fix --severity-timeout: detect connection errors (no stdout + stderr) and apply configurable severity instead of always exiting UNKNOWN - Fix --severity-stderr: remove cu() early exit so stderr flows to the analysis section where --severity-stderr is applied - Improve help texts: clarify --command accepts PowerShell pipelines, explain --winrm-domain usage, note Kerberos optionality for credentials - Add README prerequisites section with transport comparison table, Windows/Linux setup, and --winrm-domain explanation - Add README examples: pipeline, regex matching, JEA endpoint, error output - Fix README States section to match actual behavior
1 parent c36fafa commit df0d10d

File tree

3 files changed

+140
-29
lines changed

3 files changed

+140
-29
lines changed

check-plugins/by-winrm/README.md

Lines changed: 115 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,43 @@ This makes the plugin ideal for retrieving Windows-specific metrics, running cus
2121
| 3rd Party Python modules | `pypsrp` (supports JEA). Alternative without JEA: `pywinrm`, `pywinrm[kerberos]`, `pywinrm[credssp]` |
2222

2323

24+
## Prerequisites
25+
26+
### Windows (Remote Host)
27+
28+
Enable WinRM on the target Windows host:
29+
30+
```powershell
31+
Enable-PSRemoting -Force
32+
```
33+
34+
By default, WinRM listens on port **5985** (HTTP) and **5986** (HTTPS). Ensure the corresponding firewall port is open.
35+
36+
Depending on the chosen transport, additional configuration may be required:
37+
38+
| Transport | When to use | Extra Setup on Windows |
39+
|----|----|----|
40+
| `ntlm` (default) | Domain and workgroup environments. Works out of the box. | None - works with `Enable-PSRemoting`. |
41+
| `kerberos` | Active Directory environments. Most secure; supports SSO via `kinit` on the monitoring host (no password needed). | Requires AD domain membership. |
42+
| `basic` | Testing or HTTPS-only setups. Credentials are base64-encoded (not encrypted). | `winrm set winrm/config/service/auth @{Basic="true"}`. Use HTTPS in production. |
43+
| `credssp` | Multi-hop scenarios where credentials must be delegated to a third system. | `Enable-WSManCredSSP -Role Server` on the target host. |
44+
| `plaintext` | Same as `basic` but explicitly over HTTP. | Same as `basic`. Insecure - avoid in production. |
45+
46+
### Linux (Monitoring Host)
47+
48+
For **Kerberos** transport, configure `/etc/krb5.conf` for your Active Directory domain and obtain a ticket before running the plugin:
49+
50+
```bash
51+
kinit user@EXAMPLE.COM
52+
```
53+
54+
When Kerberos credentials are present in the cache, `--winrm-username` and `--winrm-password` can be omitted.
55+
56+
### `--winrm-domain`
57+
58+
When set, the username is sent as `user@DOMAIN` for NTLM authentication. Use the Active Directory domain name (e.g. `EXAMPLE.COM`). Not needed for Kerberos (the domain is part of the Kerberos principal) or local accounts.
59+
60+
2461
## Help
2562

2663
```text
@@ -40,18 +77,18 @@ usage: by-winrm [-h] [-V] [--always-ok] --command COMMAND [-c CRIT]
4077
[--winrm-transport {basic,ntlm,kerberos,credssp,plaintext}]
4178
[--winrm-username WINRM_USERNAME]
4279
43-
This plugin executes commands on remote Windows hosts by WinRM, supporting
44-
JEA. It returns standard output (STDOUT) and, in case of failure, standard
45-
error (STDERR) along with the command's exit code. By evaluating these results
46-
- through threshold checks or pattern matching on STDOUT - the plugin can
47-
generate alerts with configurable severity levels.
80+
This plugin executes PowerShell commands or scripts on remote Windows hosts
81+
via WinRM, supporting JEA. It returns standard output (STDOUT) and, in case of
82+
failure, standard error (STDERR) along with the command's exit code. By
83+
evaluating these results - through threshold checks or pattern matching on
84+
STDOUT - the plugin can generate alerts with configurable severity levels.
4885
4986
options:
5087
-h, --help show this help message and exit
5188
-V, --version show program's version number and exit
5289
--always-ok Always returns OK.
53-
--command COMMAND WinRM: Command that will be executed on the remote
54-
host.
90+
--command COMMAND PowerShell command or script to execute on the remote
91+
host. Supports pipelines and complex expressions.
5592
-c, --critical CRIT CRIT threshold for single numeric return values.
5693
Supports Nagios ranges. Example: `@10:20` alerts if
5794
STDOUT is in range 10..20.
@@ -98,16 +135,20 @@ options:
98135
PowerShell session configuration name (JEA endpoint).
99136
Only supported with pypsrp.
100137
--winrm-domain WINRM_DOMAIN
101-
WinRM Domain Name. Default: None
138+
AD domain name for NTLM authentication. When set,
139+
username is sent as user@DOMAIN. Not needed for
140+
Kerberos or local accounts. Default: None
102141
--winrm-hostname WINRM_HOSTNAME
103142
Target Windows computer on which the command will be
104143
executed.
105144
--winrm-password WINRM_PASSWORD
106-
WinRM Account Password.
145+
WinRM account password. Optional for Kerberos (uses
146+
credential cache from kinit).
107147
--winrm-transport {basic,ntlm,kerberos,credssp,plaintext}
108148
WinRM transport type. Default: ntlm
109149
--winrm-username WINRM_USERNAME
110-
WinRM Account Name.
150+
WinRM account name. Optional for Kerberos (uses
151+
credential cache from kinit).
111152
```
112153

113154

@@ -151,7 +192,38 @@ Output:
151192
2.78062697768402 [WARNING]
152193
```
153194

154-
Use Kerberos Authentication:
195+
Check if the Windows Update service is running - alert with CRIT if it is stopped (uses a pipeline and pattern matching):
196+
197+
```bash
198+
./by-winrm \
199+
--winrm-hostname=winsrv.example.com \
200+
--winrm-username=Administrator \
201+
--winrm-password=linuxfabrik \
202+
--winrm-domain=EXAMPLE.COM \
203+
--command='(Get-Service -Name wuauserv).Status' \
204+
--critical-pattern='Stopped'
205+
```
206+
207+
Output if the service is stopped:
208+
209+
```text
210+
Stopped [CRITICAL]
211+
```
212+
213+
Use regex matching - alert with WARNING if any of the last 50 system event log messages contain "disk", or CRIT if they contain "error" or "fail":
214+
215+
```bash
216+
./by-winrm \
217+
--winrm-hostname=winsrv.example.com \
218+
--winrm-username=Administrator \
219+
--winrm-password=linuxfabrik \
220+
--winrm-domain=EXAMPLE.COM \
221+
--command='Get-EventLog -LogName System -Newest 50 | Select-Object -ExpandProperty Message' \
222+
--warning-pattern='disk' \
223+
--critical-regex='error|fail'
224+
```
225+
226+
Use Kerberos authentication (no password needed when a valid ticket exists):
155227

156228
```bash
157229
kinit -V linus@EXAMPLE.COM
@@ -163,6 +235,37 @@ klist
163235
--command='Get-CpuPercent'
164236
```
165237

238+
Use a JEA (Just Enough Administration) endpoint - requires `pypsrp`:
239+
240+
```bash
241+
./by-winrm \
242+
--winrm-hostname=winsrv.example.com \
243+
--winrm-username=jea-operator \
244+
--winrm-password=linuxfabrik \
245+
--winrm-domain=EXAMPLE.COM \
246+
--winrm-configuration-name=MyJEAEndpoint \
247+
--command='Get-DiskSpace'
248+
```
249+
250+
The `--winrm-configuration-name` specifies the PowerShell session configuration (JEA endpoint) on the target host. Only the cmdlets allowed by the JEA role capability will be available.
251+
252+
What error output looks like - for example when authentication fails:
253+
254+
```bash
255+
./by-winrm \
256+
--winrm-hostname=winsrv.example.com \
257+
--winrm-username=Administrator \
258+
--winrm-password=wrong-password \
259+
--winrm-domain=EXAMPLE.COM \
260+
--command='Get-Service'
261+
```
262+
263+
Output:
264+
265+
```text
266+
the server did not respond with one of the following authentication methods - Negotiate [UNKNOWN]
267+
```
268+
166269

167270
## States
168271

@@ -182,7 +285,7 @@ Output on STDERR?
182285

183286
Return code != 0?
184287

185-
* Depending on the given `--severity-timeout`, returns OK, WARN, CRIT or UNKNOWN (default) if SSH can't connect.
288+
* Depending on the given `--severity-timeout`, returns OK, WARN, CRIT or UNKNOWN (default) if WinRM can't connect (no command output but error present).
186289
* Depending on the given `--severity-retc`, returns OK, WARN (default), CRIT or UNKNOWN if there is a return code != 0.
187290

188291

check-plugins/by-winrm/by-winrm

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ from lib.globals import (STATE_CRIT, STATE_OK, STATE_UNKNOWN, STATE_WARN)
2424

2525

2626
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
27-
__version__ = '2025111402'
27+
__version__ = '2026030301'
2828

29-
DESCRIPTION = """This plugin executes commands on remote Windows hosts by WinRM, supporting JEA.
30-
It returns standard output (STDOUT) and, in case of failure, standard error (STDERR) along with
31-
the command's exit code. By evaluating these results - through threshold checks or pattern matching
32-
on STDOUT - the plugin can generate alerts with configurable severity levels.
29+
DESCRIPTION = """This plugin executes PowerShell commands or scripts on remote Windows hosts via
30+
WinRM, supporting JEA. It returns standard output (STDOUT) and, in case of failure, standard error
31+
(STDERR) along with the command's exit code. By evaluating these results - through threshold checks
32+
or pattern matching on STDOUT - the plugin can generate alerts with configurable severity levels.
3333
"""
3434

3535
DEFAULT_SEVERITY_CONNTIMEOUT = 'unknown'
@@ -62,7 +62,8 @@ def parse_args():
6262

6363
parser.add_argument(
6464
'--command',
65-
help='WinRM: Command that will be executed on the remote host.',
65+
help='PowerShell command or script to execute on the remote host. '
66+
'Supports pipelines and complex expressions.',
6667
dest='COMMAND',
6768
required=True,
6869
)
@@ -198,7 +199,9 @@ def parse_args():
198199

199200
parser.add_argument(
200201
'--winrm-domain',
201-
help='WinRM Domain Name. '
202+
help='AD domain name for NTLM authentication. '
203+
'When set, username is sent as user@DOMAIN. '
204+
'Not needed for Kerberos or local accounts. '
202205
'Default: %(default)s',
203206
dest='WINRM_DOMAIN',
204207
default=DEFAULT_WINRM_DOMAIN,
@@ -213,7 +216,8 @@ def parse_args():
213216

214217
parser.add_argument(
215218
'--winrm-password',
216-
help='WinRM Account Password.',
219+
help='WinRM account password. '
220+
'Optional for Kerberos (uses credential cache from kinit).',
217221
dest='WINRM_PASSWORD',
218222
)
219223

@@ -228,7 +232,8 @@ def parse_args():
228232

229233
parser.add_argument(
230234
'--winrm-username',
231-
help='WinRM Account Name.',
235+
help='WinRM account name. '
236+
'Optional for Kerberos (uses credential cache from kinit).',
232237
dest='WINRM_USERNAME',
233238
)
234239

@@ -250,8 +255,6 @@ def main():
250255
if args.TEST is None:
251256
timer_start = lib.time.now('float')
252257
result = lib.winrm.run_ps(args, args.COMMAND)
253-
if result['stderr']:
254-
lib.base.cu(result['stderr'])
255258
stdout, stderr, retc = result['stdout'], result['stderr'], result['retc']
256259
else:
257260
# do not call the command, put in test data
@@ -327,7 +330,12 @@ def main():
327330

328331
# retc overwrites state from stderr
329332
if retc:
330-
retc_state = lib.base.str2state(args.SEVERITY_RETC)
333+
if not stdout and stderr:
334+
# no command output but error present - likely a connection
335+
# error (timeout, authentication failure, etc.)
336+
retc_state = lib.base.str2state(args.SEVERITY_CONNTIMEOUT)
337+
else:
338+
retc_state = lib.base.str2state(args.SEVERITY_RETC)
331339
state = lib.base.get_worst(state, retc_state)
332340

333341
# build the message

check-plugins/by-winrm/icingaweb2-module-director/by-winrm.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@
220220
"tpl-service-generic"
221221
],
222222
"max_check_attempts": 5,
223-
"notes": "This plugin executes commands on remote Windows hosts by WinRM, supporting JEA. It returns standard output (STDOUT) and, in case of failure, standard error (STDERR) along with the command's exit code. By evaluating these results - through threshold checks or pattern matching on STDOUT - the plugin can generate alerts with configurable severity levels. ",
223+
"notes": "This plugin executes PowerShell commands or scripts on remote Windows hosts via WinRM, supporting JEA. It returns standard output (STDOUT) and, in case of failure, standard error (STDERR) along with the command's exit code. By evaluating these results - through threshold checks or pattern matching on STDOUT - the plugin can generate alerts with configurable severity levels. ",
224224
"notes_url": "https://github.com/Linuxfabrik/monitoring-plugins/tree/main/check-plugins/by-winrm",
225225
"object_name": "tpl-service-by-winrm",
226226
"object_type": "template",
@@ -426,7 +426,7 @@
426426
"2": {
427427
"varname": "by_winrm_command",
428428
"caption": "By Winrm: Command",
429-
"description": "WinRM: Command that will be executed on the remote host.",
429+
"description": "PowerShell command or script to execute on the remote host. Supports pipelines and complex expressions.",
430430
"datatype": "Icinga\\Module\\Director\\DataType\\DataTypeString",
431431
"format": null,
432432
"settings": {
@@ -597,7 +597,7 @@
597597
"17": {
598598
"varname": "by_winrm_winrm_domain",
599599
"caption": "By Winrm: Winrm Domain",
600-
"description": "WinRM Domain Name.",
600+
"description": "AD domain name for NTLM authentication. When set, username is sent as user@DOMAIN. Not needed for Kerberos or local accounts.",
601601
"datatype": "Icinga\\Module\\Director\\DataType\\DataTypeString",
602602
"format": null,
603603
"settings": {
@@ -619,7 +619,7 @@
619619
"19": {
620620
"varname": "by_winrm_winrm_password",
621621
"caption": "By Winrm: Winrm Password",
622-
"description": "WinRM Account Password.",
622+
"description": "WinRM account password. Optional for Kerberos (uses credential cache from kinit).",
623623
"datatype": "Icinga\\Module\\Director\\DataType\\DataTypeString",
624624
"format": null,
625625
"settings": {
@@ -643,7 +643,7 @@
643643
"21": {
644644
"varname": "by_winrm_winrm_username",
645645
"caption": "By Winrm: Winrm Username",
646-
"description": "WinRM Account Name.",
646+
"description": "WinRM account name. Optional for Kerberos (uses credential cache from kinit).",
647647
"datatype": "Icinga\\Module\\Director\\DataType\\DataTypeString",
648648
"format": null,
649649
"settings": {

0 commit comments

Comments
 (0)