The need to to monitor arbitrary Powershell scripts comes up now and then and often there are some workarounds or alternatives, NSClient for example, named. However in order to have something I can link refer people to when the topic comes up again, I’ll try to provide a quick and simple to adapt solution. Keep in mind that this assumes you have Icinga 2 up and running on your Windows host, Powershell installed and are reasonably sane.
First the the check script I used for demonstration purposes in this case, all it does is check whether a process is running and returning OK or CRITICAL based on that.
if ($args.Length -lt 1) { Write-Output "Script requires one argument (Process)" Exit(3) } $proc=$args[0] $state = Get-Process $proc -ErrorAction SilentlyContinue if ($state) { Write-Output "PROCESS OK '$proc' is running" Exit(0) } else { Write-Output "PROCESS CRITICAL '$proc' is not running" Exit(2) }
Safe it as check_proccess.ps1 somewhere you can find it again. In this case I put next to the other check plugins.
The following are the check_command object and Service apply. And as it turns out it’s not that easy of a task as I thought, it’s mostly Windows fault really… Getting the exit code of a script from Powershell returned to icinga2 required some trickery (credit goes to NSClient for that one). The result is a bit of weird CheckCommand, which can and should be improved.
object CheckCommand "powershell" { import "plugin-check-command" command = [ "cmd" ] arguments = { "Weird command" = { value = "/c echo $powershell_script$ $powershell_args$ ; exit ($$lastexitcode) | powershell.exe -command -" description = "This is needed because powershell would not tell us the exit code otherwise" skip_key = true } } } apply Service "check_powerpoint" { import "generic-service" check_command = "powershell" vars.powershell_script = PluginDir + "\check_process.ps1" vars.powershell_args = "POWERPNT" assign where host.vars.os == "Windows" }
It should also be noted that spaces in the path really mess it up too. PluginDir in Windows is often some variation of C:\Program Files\ICINGA2\sbin , which means you need to encapsulate the path so it’s treated as one entity…. which means echo actually only echoes out the path of the script because it’s treated as a string literal for some reason….
We’ve had the best luck putting our powershell scripts in c:\scripts (and using the hacky command you’ve given us!) so space-escaping and other Windows shenanigans don’t get in our way.
The above commands works but is not very safe (when the script is not available on the server or has error parsing commands or something).
In the nsclient.ini is used this command:
ps1=cmd /c echo If (-Not (Test-Path „scripts\custom\%SCRIPT%“) ) {write-host „Script not available on server“; exit 3 }; try{ scripts\\custom\\%SCRIPT% %ARGS%} catch {Write-Host $_.Exception.Message; exit 3}; exit($lastexitcode) | powershell.exe -Noninteractive -command –
Which worked very well, but I when I try to adapt this for the Icinga2 command it fails.
I tried:
value = „/c echo If (-Not (Test-Path \“$service.vars.powershell_script$\“) ) {write-host \“Script not available on server\“; exit 3 }; try{ \“$service.vars.powershell_script$\“ $service.vars.powershell_args$} catch {Write-Host $$_.Exception.Message; exit 3}; exit($$lastexitcode) | powershell.exe -Noninteractive -command -“
There might be a better way..
Ignore my previous comment, I would highly recommend using the following CheckCommand:
object CheckCommand „check_win_powershell“{
command = [ „cmd“ ]
arguments = {
„PSCMD“ = {
value = „/c \“powershell If(-Not (Test-Path $powershell_script$) ) {write-host Script not found; exit 3}; try{ $powershell_script$ $powershell_args$ } catch {Write-Host $$_.Exception.Message; exit 3} exit($$lastexitcode)\““
skip_key = true
}
}
}
please add this to the documentation when tested 😉