Infiniroot Blog: We sometimes write, too.

Of course we cannot always share details about our work with customers, but nevertheless it is nice to show our technical achievements and share some of our implemented solutions.

Using NSClient++ and NRPE to run local WMI queries on Windows hosts

Published on October 30th 2019


A while ago (in 2016) I created an automatic Icinga2 config tool (i2ac)* for Windows hosts and Cisco switches. To create the config files for the Windows hosts, I needed to find a way to query the hosts for specific information and came across WMI. See related articles Use WMI for monitoring auto-discovery on Windows Server and Accessing WMI through a firewall - which ports are required.

* for once not open source, sorry - too customized for this specific environment

Remote WMI is good, right?

Using WMI with wmic turned out to be a good choice but there was one caveat: To list all the services on the target Windows host, a local Administrator user was required. In a large environment with a couple of hundred servers this means: Domain Admin (again, see Use WMI for monitoring auto-discovery on Windows Server why). This was always somewhat annoying to me because using a Domain Admin user for read-only purposes (such as monitoring) is just overkill and a security risk.

Today we reviewed the way the information is fetched from Windows and it was suggested why not use NSClient++ for it, because NSClient++ will at the end be the daemon used for monitoring the host. Yes and no. When I programmed i2ac, I came across a couple of problems when I used the NSClient++ output. I don't remember exactly what they were but there was a problem with getting the correct data back (filtering and output style). Anyway, in 2016 NSClient was at version 0.4.x, meanwhile there is 0.5.x out and maybe some listing/discovery options have changed.

Holy cow, NSClient++ knows WMI!

That's when I came across the CheckWMI module in NSClient++. This module enables a NRPE check_command (check_wmi) and accepts a WMI query which is then executed locally. To enable the CheckWMI module, the nsclient.ini needs to be adjusted and the CheckWMI module needs to be enabled:

; Modules
[/modules]
CheckExternalScripts = 1
CheckHelpers = 1
CheckNSCP = 1
CheckDisk = 1
CheckSystem = 1
CheckWMI = 1
NSClientServer = 1
CheckEventLog = 1
NSCAClient = 1
NRPEServer = 1
CheckLogFile = 1
SimpleFileWriter = 1
SimpleCache = 1

A comparison between a remote WMI query using wmic and a local WMI query via NSClient++ and check_nrpe shows the same output:

admck@linux:~$ /usr/bin/wmic -U domain/admin%password //windowshost 'select DeviceID from Win32_LogicalDisk WHERE DriveType = 3'
CLASS: Win32_LogicalDisk
DeviceID
C:
D:
P:

admck@linux:~$ /usr/lib/nagios/plugins/check_nrpe -H windowshost --command check_wmi -a "query=select DeviceID from Win32_LogicalDisk WHERE DriveType = 3"
C:, D:, P:|

The WMI query itself is the exact same and the output is the same too, just in another format. If the exact output style is needed, the output can be run through sed:

admck@linux:~$ /usr/lib/nagios/plugins/check_nrpe -H windowshost -c check_wmi -a 'query=select DeviceID from Win32_LogicalDisk WHERE DriveType = 3' | sed 's/[,|]//g' | sed 's/\s/\n/g'
C:
D:
P:

The biggest advantage: The remote login using the Domain Admin user (here: domain\admin) is not needed anymore!

What about services?

The reason why a Domain Admin user needed to be used was the service lookup. Without a local Administrator user not all services would be shown, leading to an incomplete service discovery and therefore to an incomplete monitoring of this Windows host. Will all services show up using the WMI query through NSClient++, too?

Service discovery (all running services) using wmic with a local Administrator:

admck@linux:~$ /usr/bin/wmic -U domain/admin%password //windowshost 'select Name from Win32_Service WHERE State = "Running"'
CLASS: Win32_Service
Name
ADSync
Appinfo
AzureADConnectHealthSyncInsights
AzureADConnectHealthSyncMonitor
BFE
BITS
BrokerInfrastructure
CertPropSvc
COMSysApp
CryptSvc
DcomLaunch
Dhcp
DiagTrack
Dnscache
DPS
EventLog
EventSystem
FontCache
gpsvc
IKEEXT
iphlpsvc
KeyIso
LanmanServer
LanmanWorkstation
lmhosts
LSM
MpsSvc
MSDTC
msoidsvc
Netlogon
netprofm
NlaSvc
nscp
nsi
pla
PlugPlay
PolicyAgent
Power
ProfSvc
RpcEptMapper
RpcSs
SamSs
Schedule
SENS
SepMasterService
SessionEnv
ShellHWDetection
Spooler
SQLWriter
SystemEventsBroker
CLASS: Win32_TerminalService
Name
TermService
CLASS: Win32_Service
Name
Themes
TrkWks
UALSVC
UmRdpService
VGAuthService
VMTools
W32Time
Wcmsvc
WinHttpAutoProxySvc
Winmgmt
WinRM
WSearch
wuauserv
Zabbix Agent

Using the WMI query via NSClient++:

admck@linux:~$ /usr/lib/nagios/plugins/check_nrpe -H windowshost -c check_wmi -a 'query=select Name from Win32_Service WHERE State = "Running"'
ADSync, Appinfo, AzureADConnectHealthSyncInsights, AzureADConnectHealthSyncMonitor, BFE, BITS, BrokerInfrastructure, CertPropSvc, COMSysApp, CryptSvc, DcomLaunch, Dhcp, DiagTrack, Dnscache, DPS, EventLog, EventSystem, FontCache, gpsvc, IKEEXT, iphlpsvc, KeyIso, LanmanServer, LanmanWorkstation, lmhosts, LSM, MpsSvc, MSDTC, msoidsvc, Netlogon, netprofm, NlaSvc, nscp, nsi, pla, PlugPlay, PolicyAgent, Power, ProfSvc, RpcEptMapper, RpcSs, SamSs, Schedule, SENS, SepMasterService, SessionEnv, ShellHWDetection, Spooler, SQLWriter, SystemEventsBroker, TermService, Themes, TrkWks, UALSVC, UmRdpService, VGAuthService, VMTools, W32Time, Wcmsvc, WinHttpAutoProxySvc, Winmgmt, WinRM, WSearch, wuauserv, Zabbix Agent|

This is working just fine, too.

TL;DR