Windows Update check Powershell Script, syntax in check_mk.user.yml?

Hi, I’m trying to get a “Windows Update” Service in check_mk 1.6.0p17 and I’m using a Windows Agent 1.6.0.12345 on a Windows Server 2019 in this example. I have managed to get it to work on one W2k19-server but I can’t repeat it.
I have to PowerShell-script, one calling the other and the return are:
OK - no pending updates.|critical=0;optional=0;hidden=0
and locally they work fine.
The line in MRPE-section of check_mk.user.yml is:
check = Windows_Update_check = c:\windows\sysnative\WindowsPowerShell\v1.0\Powershell.exe -command “.’c:\ProgramData\check_mk\agent\plugins\check_windows_update-XXXX.ps1’”

On the server I managed it to work it looks like this when I check the check_mk-services:
System Updates Open the action menu OK - 0 important updates, 0 optional updates

But on the other Windows Servers (just a couple) I can’t find this Service despite I think I done the same.

Can you post the script?
I strongly recommend not to use MRPE on Windows. Most times it is better to modify the script to produce output conform to local checks.

I get "New users can not upload … " so I just cut and paste

#################################################################################

NAME: check_windows_updates.ps1

COMMENT: Script to check for windows updates with Nagios + NRPE/NSClient++

Checks:

- how many critical and optional updates are available

- whether the system is waiting for reboot after installed updates

Features:

- properly handles NRPE’s 1024b limitation in return packet

- configurable return states for pending reboot and optional updates

- performance data in return packet shows titles of available critical updates

- caches updates in file to reduce network traffic, also dramatically increases script execution speed

Return Values for NRPE:

No updates available - OK (0)

Only Hidden Updates - OK (0)

Updates already installed, reboot required - WARNING (1)

Optional updates available - WARNING (1)

Critical updates available - CRITICAL (2)

Script errors - UNKNOWN (3)

NRPE Handler to use with NSClient++:

[NRPE Handlers]

check_updates=cmd /c echo scripts\check_windows_updates.ps1 $ARG1$ $ARG2$; exit $LastExitCode | powershell.exe -command -

IMPORTANT: Please make absolutely sure that your Powershell ExecutionPolicy is set to Remotesigned.

Also note that there are two versions of powershell on a 64bit OS! Depending on the architecture

of your NSClient++ version you have to choose the right one:

64bit NSClient++ (installed under C:\Program Files ):

%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe “Set-ExecutionPolicy RemoteSigned”

32bit NSClient++ (installed under C:\Program Files (x86) ):

%SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe “Set-ExecutionPolicy RemoteSigned”

CHANGELOG:

1.45 2016-08-05 - corrected some typos, added newline after each critical update

1.44 2016-04-05 - performance data added

1.42 2015-07-20 - strip unwanted characters from returnString

1.41 2015-04-24 - removed wuauclt /detectnow if updates available

1.4 2015-01-14 - configurable return state for pending reboot

1.3 2013-01-04 - configurable return state for optional updates

1.2 2011-08-11 - cache updates, periodically update cache file

1.1 2011-05-11 - hidden updates only -> state OK

- call wuauctl.exe to show available updates to user

1.0 2011-05-10 - initial version

#################################################################################

Copyright © 2011-2015 Christian Kaufmann, ck@tupel7.de

This program is free software; you can redistribute it and/or modify it under

the terms of the GNU General Public License as published by the Free Software

Foundation; either version 3 of the License, or (at your option) any later

version.

This program is distributed in the hope that it will be useful, but WITHOUT

ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS

FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with

this program; if not, see http://www.gnu.org/licenses.

#################################################################################

$htReplace = New-Object hashtable
foreach ($letter in (Write-Output ä ae ö oe ü ue Ä Ae Ö Oe Ü Ue ß ss)) {
$foreach.MoveNext() | Out-Null
$htReplace.$letter = $foreach.Current
}
$pattern = “[$(-join $htReplace.Keys)]”

$returnStateOK = 0
$returnStateWarning = 1
$returnStateCritical = 2
$returnStateUnknown = 3
$returnStatePendingReboot = $returnStateWarning
$returnStateOptionalUpdates = $returnStateOK

$updateCacheFile = “check_windows_updates-cache.xml”
$updateCacheExpireHours = “24”

$logFile = “check_windows_update.log”

function LogLine( [String]$logFile = $(Throw ‘LogLine:$logFile unspecified’),
[String]$row = $(Throw ‘LogLine:$row unspecified’)) {
$logDateTime = Get-Date -Format ‘yyyy-MM-dd HH:mm:ss’
Add-Content -Encoding UTF8 $logFile ($logDateTime + " - " + $row)
}

if (Test-Path “HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired”){
Write-Host “updates installed, reboot required”
if (Test-Path $logFile) {
Remove-Item $logFile | Out-Null
}
if (Test-Path $updateCacheFile) {
Remove-Item $updateCacheFile | Out-Null
}
exit $returnStatePendingReboot
}

if (-not (Test-Path $updateCacheFile)) {
LogLine -logFile $logFile -row ("$updateCacheFile not found, creating…")
$updateSession = new-object -com “Microsoft.Update.Session”
$updates=$updateSession.CreateupdateSearcher().Search((“IsInstalled=0 and Type=‘Software’”)).Updates
Export-Clixml -InputObject $updates -Encoding UTF8 -Path $updateCacheFile
}

if ((Get-Date) -gt ((Get-Item $updateCacheFile).LastWriteTime.AddHours($updateCacheExpireHours))) {
LogLine -logFile $logFile -row (“update cache expired, updating…”)
$updateSession = new-object -com “Microsoft.Update.Session”
$updates=$updateSession.CreateupdateSearcher().Search((“IsInstalled=0 and Type=‘Software’”)).Updates
Export-Clixml -InputObject $updates -Encoding UTF8 -Path $updateCacheFile
} else {
LogLine -logFile $logFile -row (“using valid cache file…”)
$updates = Import-Clixml $updateCacheFile
}

$criticalTitles = “”;
$countCritical = 0;
$countOptional = 0;
$countHidden = 0;

if ($updates.Count -eq 0) {
Write-Host “OK - no pending updates.|critical=$countCritical;optional=$countOptional;hidden=$countHidden”
exit $returnStateOK
}

foreach ($update in $updates) {
if ($update.IsHidden) {
$countHidden++
}
elseif ($update.AutoSelectOnWebSites) {
$criticalTitles += $update.Title + " `n"
$countCritical++
} else {
$countOptional++
}
}
if (($countCritical + $countOptional) -gt 0) {
$returnString = “Updates: $countCritical critical, $countOptional optional” + [Environment]::NewLine + “$criticalTitles”
$returnString = [regex]::Replace($returnString, $pattern, { $htReplace[$args[0].value] })

# 1024 chars max, reserving 48 chars for performance data -> 
if ($returnString.length -gt 976) {
    Write-Host ($returnString.SubString(0,975) + "|critical=$countCritical;optional=$countOptional;hidden=$countHidden")
} else {
    Write-Host ($returnString + "|critical=$countCritical;optional=$countOptional;hidden=$countHidden")
}   

}

#if ($countCritical -gt 0 -or $countOptional -gt 0) {

Start-Process “wuauclt.exe” -ArgumentList “/detectnow” -WindowStyle Hidden

#}

if ($countCritical -gt 0) {
exit $returnStateCritical
}

if ($countOptional -gt 0) {
exit $returnStateOptionalUpdates
}

if ($countHidden -gt 0) {
Write-Host “OK - $countHidden hidden updates.|critical=$countCritical;optional=$countOptional;hidden=$countHidden”
exit $returnStateOK
}

Write-Host “UNKNOWN script state”
exit $returnStateUnknown

Why don’t you just use the windows_updates.vbs agent plugin that comes with checkmk?

I started with that but had some problem, the script worked locally but I never got it to work from the Agent. Then I saw there was a PowerShell-solution and that felt more like the future.
The .vbs.script I ran worked when I put cscript before the .vbs locally but when I tried to do the same in the .yml-file I got like wrong syntax.

This was the syntax I tried for the .vbs-script

  • check = WindowsUpdates ‘C:\ProgramData\CheckMK\Agent\mrpe\windows_updates.vbs’ -w 10 -c 20 MyParameter

in the MRPE section och the .yml-file

Again - don’t use MRPE on Windows
The “windows_updates.vbs” is a real CheckMK plugin. You only need to put it inside the directory “C:\Programdata\checkmk\agent\plugins” and then you create an entry inside the check_mk_user.yml for the execution time and

plugins:
  execution:
    - pattern     : '$CUSTOM_PLUGINS_PATH$\windows_updates.vbs'
      timeout     : 3600
      run         : yes
      async       : yes
      cache_age   : 90000

Yes, thank’s, now the .vbs-script works :slight_smile: !
So if I should get a general Powershell-script to work I will try to implement it in the plugin-in-section as I now did with the .vbs?

Yes and no. Scripts inside the plugin section also need a check script on CMK server site.
What you can do is a local check. This will then be placed inside the “/local” folder and can also be configured the same way with cache age.

Your windows update PowerShell script as local check as an example

$rebootpending = 0
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") {
    Write-Host "updates installed, reboot required"
    $rebootpending = 1
}

$updateSession = New-Object -com "Microsoft.Update.Session"
$updates = $updateSession.CreateupdateSearcher().Search(("IsInstalled=0 and Type='Software'")).Updates
$criticalTitles = "";
$countCritical = 0;
$countOptional = 0;
$countHidden = 0;

if ($updates.Count -eq 0) {
    Write-Host "P WindowsUpdates critical=$countCritical;1;2|optional=$countOptional;5;10|hidden=$countHidden no pending updates"
}
else {
    foreach ($update in $updates) {
        if ($update.IsHidden) {
            $countHidden++
        }
        elseif ($update.AutoSelectOnWebSites) {
            $criticalTitles += " \n " + $update.Title
            $countCritical++
        }
        else {
            $countOptional++
        }
    }
    Write-Host "P WindowsUpdates critical=$countCritical;1;1|optional=$countOptional;1;100|hidden=$countHidden|reboot=$rebootpending;1 pending updates $criticalTitles"
}

Ok, I’ll have to do some testing about this.
Thank’s a lot for good and fast support :).

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed. Contact @fayepal if you think this should be re-opened.