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!