mickem / nscp

NSClient++
http://nsclient.org
GNU General Public License v2.0
239 stars 94 forks source link

Return error when external script not found #207

Closed willemdh closed 8 years ago

willemdh commented 8 years ago

Is there some way to make NSClient++ return a critical or unknown status when an external script is not present on a monitored server. At this moment this is returned:

scripts\powershell\check_ms_win_disk_load.ps1 : The module 'scripts' could not
be loaded. For more information, run 'Import-Module scripts'.

At line:1 char:1

+ scripts\\powershell\\check_ms_win_disk_load.ps1 -ms 5 -dl C; exit $LastExitCode

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : ObjectNotFound: (scripts\\powersh...n_disk_load.p 

s1:String) [], CommandNotFoundException

+ FullyQualifiedErrorId : CouldNotAutoLoadModule

The problem is the returned status is 'ok', which makes it hard to notice this when an external (Powershell) script is not on the monitored server.

Or is there already a way to make it exit with status code 2 or 3 when the external script is not present?

mickem commented 8 years ago

This can be done by changing the "wrapping a bit", probably should make this default really...

[/modules]
CheckExternalScripts = enabled

[/settings/external scripts/wrapped scripts]
missing = missing.ps1 
ok = check_test.ps1 

[/settings/external scripts/wrappings]
ps1 = cmd /c echo If (-Not (Test-Path "scripts\%SCRIPT%") ) { exit(3) }; scripts\\%SCRIPT% %ARGS%; exit($lastexitcode) | powershell.exe -command -

The result:

ok
L        cli OK: Test arguments are: ( "" "")
missing
L        cli UNKNOWN: No output available from command (missing).
willemdh commented 8 years ago

Thanks. This works for me.

willemdh commented 8 years ago

Just fyi, it might be a good idea to also add /noprofile as a default to prevent issues with server with Exchange, Citrix or VMware modules.

ps1 = cmd /c echo If (-Not (Test-Path "scripts\%SCRIPT%") ) { exit(3) }; scripts\\%SCRIPT% %ARGS%; exit($lastexitcode) | powershell.exe /noprofile -command -
willemdh commented 8 years ago

More fyi. Powershell scripts should have their own folder in the NSClient scripts folder. It's easier and more logical to separate them from the rest, just like you are doing for lua and Python.

The final wrapper command I'm using atm is:

ps1 = cmd /c echo If (-Not (Test-Path "scripts\powershell\%SCRIPT%") ) { exit(3) };  scripts\powershell\%SCRIPT% %ARGS%; exit($lastexitcode) | powershell.exe /noprofile -command -

Grtz

willemdh commented 8 years ago

I might have found a bug with the ps1 wrapper. %ARGS% seems to be empty somehow. As a test I made this:

ps1 = cmd /c echo If (-Not (Test-Path "scripts\\powershell\\%SCRIPT%") ) { exit(3) }; write-host "Args: %ARGS%"; scripts\\powershell\\%SCRIPT% %ARGS%; exit($lastexitcode) | powershell.exe /noprofile -command -

When I execute:

/usr/local/nagios/libexec/check_nrpe -H server -c check_ms_win_disk_load -a '-ms 5 -dl F'

nsclient.ini:

[/settings/external scripts/wrapped scripts]
check_ms_win_disk_load                  = check_ms_win_disk_load.ps1

I should get an error as F does not exist. I always get:

Args:

With nothing as argument. Or am I missing something? Could someone please try this out?

willemdh commented 8 years ago

Ok, found the problem. It is indeed %ARGS% that does not work. What does work is $ARG1$

mickem commented 8 years ago

I should fix that though...

willemdh commented 8 years ago

Yes might be a good idea. There is still an issue with the wrapper by the way. As a test I renames a script I'm calling through the wrapper.

PS H:\> test-path "C:\Program Files\NSClient++\scripts\powershell\check_ms_win_network_connections.ps1.bak"
True
PS H:\> test-path "C:\Program Files\NSClient++\scripts\powershell\check_ms_win_network_connections.ps1"
False
ps1 = cmd /c echo If (-Not (Test-Path "scripts\\powershell\\%SCRIPT%") ) { exit(3) }; scripts\\powershell\\%SCRIPT% $ARG1$; exit($lastexitcode) | powershell.exe /noprofile -command -

In Nagios however I still have an OK state and this messgae:

scripts\powershell\check_ms_win_network_connections.ps1 : The module 'scripts'
could not be loaded. For more information, run 'Import-Module scripts'.

At line:1 char:1

+ scripts\\powershell\\check_ms_win_network_connections.ps1 -H localhost; exit $L

ast ...

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : ObjectNotFound: (scripts\\powersh...connections.p 

s1:String) [], CommandNotFoundException

+ FullyQualifiedErrorId : CouldNotAutoLoadModule

This is not correct. i'm not sure how though yet.

willemdh commented 8 years ago

Could you please re-open this untill we find a working solution to exit 3 when the script is not found?

I have done some tests and used the full path.

ps1 = cmd /c echo If (-Not (Test-Path "C:\Program Files\NSClient++\scripts\powershell\%SCRIPT%") ) { Write-Host "Script not found"; exit (3) } else { & "C:\Program Files\NSClient++\scripts\powershell\%SCRIPT% $ARG1$"; exit($lastexitcode) } | powershell.exe /noprofile -command -

But even then I keep getting:

scripts\powershell\check_ms_win_network_connections.ps1 : The module 'scripts'
could not be loaded.

It seems like it's completely ignoring the { Write-Host "Script not found"; exit 3 } In Powershell ISE the command is working fine. To get it working in command prompt it took some extra quoting fro the space in program files, but like this it works in command prompt:

C:\Windows\system32>cmd /c echo If (-Not (Test-Path "C:\Program Files\NSClient++\scripts\powershell\check_ms_win_network
_connections.ps1") ) { Write-Host "Script not found" } else { Invoke-Expression 'C:\"Program Files"\NSClient++\scripts\p
owershell\check_ms_win_network_connections.ps1' } | powershell.exe /noprofile -command -
Script not found

When I use exactly the same in NSClient.ini it doesn't work however:

cmd /c echo If (-Not (Test-Path "C:\Program Files\NSClient++\scripts\powershell\check_ms_win_network_connections.ps1") ) { Write-Host "Script not found" } else { Invoke-Expression 'C:\"Program Files"\NSClient++\scripts\powershell\check_ms_win_network_connections.ps1' } | powershell.exe /noprofile -command -
mickem commented 8 years ago

You can reopen this yourself (just click reoprn).

Though I am not sure I see whats wrong:

The following config:

[/modules]
CheckExternalScripts = 1

[/settings/external scripts/wrapped scripts]
o1=check_test.ps1
m1=check_missing.ps1

o2=check_test.ps1 1 2 3
m2=check_missing.ps1 1 2 3

o3=check_test.ps1 $ARGS$
m3=check_missing.ps1 $ARGS$

Yields the following result:

o1
L        cli OK: Test arguments are: ( "" "")
m1
L        cli UNKNOWN: Script not found
o2
L        cli OK: Test arguments are: (1 "2" "3")
m2
L        cli UNKNOWN: Script not found
o3 1 2 3
L        cli OK: Test arguments are: (1 "2" "3")
m3 1 2 3
L        cli UNKNOWN: Script not found
willemdh commented 8 years ago

Michael, I can't reopen issues (even my own) if they are closed by a collaborator. Check this StackOverflow Answer for more info on re-opening issues.

http://stackoverflow.com/questions/21333654/how-to-re-open-an-issue-in-github

I'll test again asap. Did you test with %ARGS% or with $ARGS$? As I was pretty sure %ARGS% didn't work for me.

mickem commented 8 years ago

Sorry had no idea

mickem commented 8 years ago

No %ARGS will work in the next version

willemdh commented 8 years ago

Michael,

I have been testing several combinations for some time... And I definitely get some inconsistent results. It might have something to do with underscores in in the wrappers.

My nsclient.ini:

[/settings/external scripts/wrapped scripts]
o1=check_test.ps1
m1=check_missing.ps1

o1_und=check_test.ps1
m1_und=check_missing.ps1

o2=check_test.ps1 1 2 3
m2=check_missing.ps1 1 2 3

o2_und=check_test.ps1 1 2 3
m2_und=check_missing.ps1 1 2 3

o3=check_test.ps1 $ARGS$
m3=check_missing.ps1 $ARGS$

check_ms_win_network_connections=check_ms_win_network_connections.ps1
m4=check_missing.ps1

[/settings/external scripts/wrappings]
bat = scripts\\%SCRIPT% %ARGS%
vbs = cscript.exe //T:30 //NoLogo scripts\\lib\\wrapper.vbs %SCRIPT% %ARGS%
# ps1 = cmd /c echo scripts\\%SCRIPT% %ARGS%; exit($lastexitcode) | powershell.exe -command -
# ps1 = cmd /c echo If (-Not (Test-Path "scripts\powershell\%SCRIPT%") ) { Write-Host "UNKNOWN: Script not found"; exit(3) }; scripts\\powershell\\%SCRIPT% $ARGS$; exit($lastexitcode) | powershell.exe -command -
ps1 = cmd /c echo If (-Not (Test-Path "scripts\%SCRIPT%") ) { Write-Host "UNKNOWN: Script not found"; exit(3) }; scripts\\%SCRIPT% $ARGS$; exit($lastexitcode) | powershell.exe -command -
# ps1 = cmd /c echo If (-Not (Test-Path scripts\powershell\%SCRIPT%) ) { Write-Host "Script not found"; exit 3 } else { Invoke-Expression 'C:\"Program Files"\NSClient++\scripts\powershell\%SCRIPT%' "$ARG1$"; exit($lastexitcode) } | powershell.exe /noprofile -command -

And the result:

image

One thing that is consistent is that although I specify

Write-Host "UNKNOWN: Script not found"; exit(3)

The "UNKNOWN: Script not found" is never shown. Also why am I getting 'Unknown command(s): o2_und' while it definitely is there??

Could you do a test with wrappers with underscores? I'm hoping you get similar results, so I'm sure I'm not going crazy here.. :)

willemdh commented 8 years ago

Hmmm very weird.. I had a nscp test running. As I had other plans I stopped it and now suddenly I see the "UNKNOWN: Script not found" on my Nagios server. is it possible a config is not reloaded when nscp test is running? Check it out. I changed nothing compared to the previous screenshot except stopping the nscp test and now it seems to work as expected:

image

:confused:

Just tested this again and it seem like some parts of the nsclient.ini config are not loaded sometimes. So I add:

o4=check_test.ps1 $ARGS$

to the nsclient.ini above and restarted nscp service. Result: Unknown command(s): o4

And after stopping the nscp test it suddenly started working. Damn.. If I only knew this yesterday.

Grtz

mickem commented 8 years ago

Config is only reloaded when you restart nsclient++

mickem commented 8 years ago

But one thing which isimportant is that "test" is an actual server instance of NSCLient++ so you have to stop nsclient++ service before you run test (or the servide will be responding to your queries... And chaning the config requires you to stop/start test mode for it to reload.

willemdh commented 8 years ago

Ok. Thanks for the info. I have tuned the ps1 wrapper still a little bit, so it contains the missing script in the error message.

ps1 = cmd /c echo If (-Not (Test-Path "scripts\powershell\%SCRIPT%") ) { Write-Host "UNKNOWN: Script `"%SCRIPT%`" not found."; exit(3) }; scripts\powershell\%SCRIPT% $ARGS$; exit($lastexitcode) | powershell.exe /noprofile -command -

Also omitted the double backslash as that seems not necessary?

image

f-vt commented 4 years ago

Hi !

Double backslash is needed. Thanks for this thread, exactly what I looked for.

Personnaly I prefer to specify path in wrapped scripts like this:

[/settings/external scripts/wrappings]
;Enhanced powershell scripts wrapping with error if file not exists
ps1 = cmd /c echo If (-Not (Test-Path "%SCRIPT%") ) { Write-Host "UNKNOWN: Script `"%SCRIPT%`" not found."; exit(3) }; %SCRIPT% %ARGS%; exit($lastexitcode) | powershell.exe -NoProfile -ExecutionPolicy Bypass -command -
[/settings/external scripts/wrapped scripts]
checkname= scripts\PS\Script.ps1 -arg1 decimalargvalue -arg2 "stringargvalue"