My colleagues have been getting a little frustrated by the “Plugin Timeout” messages in Nagios resulting from the length of time it takes to check for Windows Updates. I had been using Jules Check for Windows Updates that essentially boils down to calling:
$updateSession = new-object -com "Microsoft.Update.Session"
$updates=$updateSession.CreateupdateSearcher().Search(("IsInstalled=0 and Type='Software'")).Updates
So I took Jules’ work and divided the powershell script into two. One script is called on a scheduled basis (say every 30mins) and writes the result to a text file. When Nagios runs the check for windows updates it calls the other script that parses the output of the text file rather than running a new update session object (the time-consuming bit).
So create the two files. I created them in C:\scripts:
- check_windows_updates_scheduled.ps1
- check_windows_updates.ps1
Use the following code:
check_win_updates_scheduled.ps1
# ###########################################################
# check_win_updates_scheduled.ps1 by Jonny McCullagh 20140109
# This powershell script should be called as a scheduled task
# Output is sent to a text file. The text file is then read by
# check_win_updates.ps1
# to answer the nagios call. This saves waiting for the slow
# windows update check.
# Only required change is the path to the temp file below
# ###########################################################
$strPathToTempFile="c:\scripts\check_win_updates.txt"
$countHidden=0
$countCritical=0
$countOptional=0
# ###########################################################
# Check if installed updates require a reboot first
# ###########################################################
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"){
$strOutput = "Updates installed, Reboot required"
Out-File -filepath $strPathToTempFile -inputobject $strOutput
exit 0
}
# ###########################################################
# Perform the actual update lookup
# ###########################################################
$updateSession = new-object -com "Microsoft.Update.Session"
$updates=$updateSession.CreateupdateSearcher().Search(("IsInstalled=0 and Type='Software'")).Updates
# ###########################################################
# Loop through each update to count each type of update
# ###########################################################
foreach($update in $updates) {
if ($update.IsHidden) {
$countHidden++
}elseif($update.AutoSelectOnWebSites) {
$criticalTitles += $update.Title + " "
$countCritical++
}else{
$countOptional++
}
}
# ###########################################################
# Create some strings ready to write out to the output file
# ###########################################################
$strHiddenText="$countHidden Hidden";
$strCriticalText="$countCritical Critical";
$strOptionalText="$countOptional Optional";
# ###########################################################
# Write a string to the output file to be read by check_win_updates.ps1
# ###########################################################
$strOutput = "$strCriticalText $strOptionalText $strHiddenText"
Out-File -filepath $strPathToTempFile -inputobject $strOutput
check_windows_updates.ps1
# ###########################################################
# check_win_updates.ps1 by Jonny McCullagh 20140109
# This powershell script should be called by Nagios and will
# warn if windows updates are available but based on the
# text output from another powershell script
# (check_win_updates_available.ps1)
# that runs as a scheduled task
# Only required change is the path to the temp file below
# ###########################################################
$strPathToTempFile="c:\scripts\check_win_updates.txt"
$countHidden=0
$countCritical=0
$countOptional=0
# ###########################################################
# Get the output from the scheduled task and see if any
# updates are available
# ###########################################################
if (!(Test-Path $strPathToTempFile)) {
Write-Host "Input file not available. Has scheduled task run check_win_updates_scheduled.ps1"
exit 2
}
$strInput = Get-Content $strPathToTempFile
$arrInput = $strInput.split(" ")
$numCritical=$arrInput[0]
$numOptional=$arrInput[2]
$numHidden=$arrInput[4]
# ###########################################################
# Write out the results based on the number of updates
# ###########################################################
if($numOptional -eq "Reboot"){
write-host "WARNING "$strInput
exit 1
}elseif($numCritical -gt 0){
write-host "CRITICAL Updates Available"$strInput
exit 2
}elseif($numOptional -gt 0){
write-host "WARNING Updates Available"$strInput
exit 1
}elseif($numHidden -gt 0){
write-host "OK Only Hidden Updates Available "$strInput
exit 0
}else{
write-host "OK No Windows Updates "$strInput
exit 0
}
Add the following to your nsclient.ini
[/settings/external scripts/scripts] windows_updates=cmd /c echo C:\scripts\check_win_updates.ps1; exit $LastExitCode | powershell.exe -command -
And that can be called with the following in the Nagios commands.cfg :
define command {
command_name check_windows_updates
command_line $USER1$/check_nrpe -H $HOSTADDRESS$ -c windows_updates -t 120
}
Create the Scheduled Task for check_windows_updates_scheduled.ps1
Choose ‘Create Task’
Give your Task a name and description and ensure it runs as a user with sufficient privileges:
Under the Trigger tab choose a schedule of say 30 minutes:
For the Action tab choose ‘Start a Program’ and enter the following text in the script field:
C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe “& ‘c:\scripts\check_windows_updates_scheduled.ps1′”
After saving you should have a Scheduled Task similar to the one below.![]()


Hi Jonny, I have been trying to get windows updates checks on nagios for a month before giving up and by chance I came across this post on google. After using your recommendation for jules’ Check Windows Updates using Powershell script I had the checking working in 5 minutes. I don’t have timeout issues, yet, if I do I will take your suggestion for dumping the report to a log file. Thank you!!
good work, i just add some things to work…
1 – A command line to launch the task with the correct execution policy and spaces in the path
PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& ‘C:\Program Files\NSClient++\scripts\check_win_updates_scheduled.ps1′”
2 – A function that return the script path to create the text file
function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}
then modify script like this, sorry i don’t know how to do this in one line but it works !
$strPathToTempFile=Get-ScriptDirectory
$strPathToTempFile+=”\check_win_updates.txt”
thanks
Hello i got one issue with the scripts. It find on one server 1 optional update. The other original script does not find anyhing. Also the windows update dialog finds nothing. Do you know how the fix that?
Thanks for this; I needed a ‘distributed’ Windows Updates check and this is what I have been deploying on my servers to replace the previous method I used which was on-demand from Nagios and would often time out.
It works well except for a few servers where I have the same issue as Ronald above, i.e. 1 optional update but nothing seems available. What I did find, is if I run the scheduled script manually, it returns 0 for optional updates but when run by Task Scheduler it returns 1 optional… which is bizarre but could be related to permissions so I will investigate that further.
UPDATE to above comment: Issue sorted. I needed to check the box in the Scheduled Task “Run with highest privileges”.
Again, thanks for this post!