http://www.perlmonks.org?node_id=941457

natxo has asked for the wisdom of the Perl Monks concerning the following question:

at $work I wrote a nagios plugin to check the status of scheduled tasks on windows servers. It parses the output of schtasks as csv. The problem with monitoring stuff is that you find stuff you did not know in the first place :-). As a rule of thumb, if a scheduled task in windows server has run ok, it shows as "result" 0. But sometimes, jobs that have run properly exit with another errorlevel. So I would like to exclude some jobs/results combinations in the plugin. I could hardwire it in the plugin itself, but this would not be portable so ideally I would like to do this from a cli option. This is what I have so far:
#!/usr/bin/perl use strict; use warnings; use Getopt::Long; use Pod::Usage; use Text::CSV_XS; # variables my ( $version, $revision, $help, %lastresult_of, $checknow, %exclusion +s, %lastresult_excl ); my %ERRORS = ( 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3, 'DEPENDENT' => 4, ); $version = '1.1'; Getopt::Long::Configure( "no_ignore_case", "bundling" ); GetOptions( 'c|checknow' => \$checknow, 'h|help|?' => \$help, 'V|version' => \$revision, 'e|exclude=s%' => sub{ push ( @{$exclusions{$_[1]}}, $_[2] ) }, ); # run schtaks, keep output in JOBS memory handle # switches for schtasks.exe: # /query: get the list of scheduled jobs # /fo csv: dump the list as in csv format # /v: verbose # open (JOBS, "schtasks /query /fo csv /v |") or die "couldn't exec sc +htasks: $!\n"; # create a Text::CSV_XS object my $csv = Text::CSV_XS->new(); # parse JOBS memory handle. The output is a csv file. The second colum +n ($columns[1] is "Taskname", # the 7th $columns[6] is "Last Result". I only need the values of "Las +t Result" which are NOT 0 (0 is good, it means it ran well). # Because in windows 2008 the task scheduler has been revamped, there +are a lot of new scheduled jobs that are not important, so I # filter them in the next if statements while ( my $line = <DATA> ) { chomp $line; last if $line =~ /^INFO: There are no scheduled tasks.*$/; if ( $csv->parse($line) ) { my @columns = $csv->fields(); next if $columns[1] eq "TaskName"; # skip the header next if $columns[3] eq "Disabled"; # skip if 4th column is 'di +sabled' next if $columns[2] eq "Disabled"; # skip if next run time is +'disabled' next if $columns[3] eq "Running"; # skip if the task is runni +ng now next if $columns[18] eq "At logon time"; # skip if 19th colum is 'At logon ti +me" next if $columns[5] eq "N/A"; # skip if last run time is em +pty # if last result is other than 0, save taskname and last result in the + %lastresult_of if ( $columns[6] != 0 ) { $lastresult_of{ $columns[1] } = $columns[6]; } } } # if the %lastresult_of is empty, this will be zero if ( scalar keys %lastresult_of == 0 ) { print "0K: All scheduled tasks seem to have run fine\n"; exit $ERRORS{OK}; } else { while ( my ( $key, $value ) = each(%lastresult_of) ) { print "WARNING: scheduled task [$key] finished with error [$va +lue]\n"; exit $ERRORS{WARNING}; } } __DATA__ "HostName","TaskName","Next Run Time","Status","Logon Mode","Last Run +Time","Last Result","Creator","Schedule","Task To Run","Start In","Co +mment","Scheduled Task State","Scheduled Type","Start Time","Start Da +te","End Date","Days","Months","Run As User","Delete Task If Not Resc +heduled","Stop Task If Runs X Hours and X Mins","Repeat: Every","Repe +at: Until: Time","Repeat: Until: Duration","Repeat: Stop If Still Run +ning","Idle Time","Power Management" "host","Defrag C","04:00:00, 09-10-2011","","Interactive/Background"," +04:00:00, 02-10-2011","0","SYSTEM","At 04:00 every Sun of every week, + starting 26-05-2010","C:\WINDOWS\system32\defrag.exe c:","C:\WINDOWS +\system32","N/A","Enabled","Weekly","04:00:00","26-05-2010","N/A","SU +NDAY","N/A","domain\SVC.Scheduler","Disabled","72:0","Disabled","Disa +bled","Disabled","Disabled","Disabled","No Start On Batteries, Stop O +n Battery Mode" "host","DkTknSrv","05:00:00, 07-10-2011","","Interactive/Background"," +05:00:00, 06-10-2011","0","SYSTEM","At 05:00 every day, starting 05-0 +5-2011","d:\scripts\DkTknSrv\DkTknSrv.cmd ","d:\scripts\DkTknSrv","N/ +A","Enabled","Daily ","05:00:00","05-05-2011","N/A","Everyday","N/A", +"domain\SVC.Scheduler","Disabled","72:0","Disabled","Disabled","Disab +led","Disabled","Disabled","No Start On Batteries, Stop On Battery Mo +de" "host","do stuff then","15:32:00, 06-10-2011","","Interactive/Backgrou +nd","14:32:00, 06-10-2011","0","SYSTEM","Every 1 hour(s) from 21:32 f +or 24 hour(s) every day, starting 16-02-2011","d:\perl\bin\perl.exe d +:\scripts\dostuff.pl","d:\perl\bin","N/A","Enabled","Hourly ","21:32: +00","16-02-2011","N/A","Everyday","N/A","domain\SVC.Scheduler","Disab +led","72:0","1 Hour(s)","None","24 Hour(s): 0 Minute(s)","Disabled"," +Disabled","No Start On Batteries, Stop On Battery Mode" "host","Memory Optimization Schedule","Disabled","","Background only", +"Never","0","SYSTEM","Disabled","C:\Program Files\Citrix\Server Resou +rce Management\Memory Optimization Management\Program\CtxBace.exe -op +timize","N/A","N/A","Disabled","At system start up","At system start +up","01-01-2001","N/A","N/A","N/A","NT AUTHORITY\SYSTEM","Disabled"," +72:0","Disabled","Disabled","Disabled","Disabled","Disabled","No Star +t On Batteries, Stop On Battery Mode" "host","Memory Optimization Schedule","Disabled","","Background only", +"Never","0","SYSTEM","Disabled","C:\Program Files\Citrix\Server Resou +rce Management\Memory Optimization Management\Program\CtxBace.exe -op +timize","N/A","N/A","Disabled","Hourly ","03:00:00","01-01-1999","N/A +","Everyday","N/A","NT AUTHORITY\SYSTEM","Disabled","72:0","Disabled" +,"Disabled","Disabled","Disabled","Disabled","No Start On Batteries, +Stop On Battery Mode" "host","perfmon-srv","02:00:00, 07-10-2011","","Interactive/Background +","02:00:09, 06-10-2011","0","SYSTEM","At 02:00 every day, starting 0 +2-07-2010","d:\scripts\startup\termserv.cmd ","d:\scripts\startup","N +/A","Enabled","Daily ","02:00:00","02-07-2010","N/A","Everyday","N/A" +,"domain\SVC.Scheduler","Disabled","72:0","Disabled","Disabled","Disa +bled","Disabled","Disabled","No Start On Batteries, Stop On Battery M +ode" "host","blabla","At system start up","","Interactive/Background","01:3 +6:17, 06-10-2011","0","administrator","Run at system startup","d:\scr +ipts\bla\prog.vbs ","d:\scripts\bla","N/A","Enabled","At system start + up","At system start up","02-02-2010","N/A","N/A","N/A","domain\SVC. +Scheduler","Disabled","72:0","Disabled","Disabled","Disabled","Disabl +ed","Disabled","No Start On Batteries, Stop On Battery Mode" "host","robocopy dir","15:22:00, 06-10-2011","","Interactive/Backgroun +d","14:22:00, 06-10-2011","3","SYSTEM","Every 1 hour(s) from 02:22 fo +r 24 hour(s) every day, starting 06-09-2011","d:\scripts\robocopy.exe + source d:\dir /copyall /mir /purge /r:2 /w:3 /xf program.exe /xd arc +hive /np /log+:d:\scripts\logs\robocopy.log","d:\scripts","N/A","Enab +led","Hourly ","02:22:00","06-09-2011","N/A","Everyday","N/A","domain +\SVC.Scheduler","Disabled","72:0","1 Hour(s)","None","24 Hour(s): 0 M +inute(s)","Disabled","Disabled","No Start On Batteries, Stop On Batte +ry Mode" "host","shutdown","01:30:00, 07-10-2011","","Interactive/Background"," +01:30:00, 06-10-2011","0","SYSTEM","At 01:30 every day, starting 04-1 +2-2009","d:\scripts\shutdown\shutdown.cmd ","d:\scripts\shutdown","N/ +A","Enabled","Daily ","01:30:00","04-12-2009","N/A","Everyday","N/A", +"domain\SVC.Scheduler","Disabled","72:0","Disabled","Disabled","Disab +led","Disabled","Disabled","No Start On Batteries, Stop On Battery Mo +de" "host","startup","At system start up","","Interactive/Background","01: +36:10, 06-10-2011","0","SYSTEM","Run at system startup","d:\Scripts\S +tartup\startup.cmd ","d:\Scripts\Startup","N/A","Enabled","At system +start up","At system start up","04-12-2009","N/A","N/A","N/A","domain +\SVC.Scheduler","Disabled","72:0","Disabled","Disabled","Disabled","D +isabled","Disabled","No Start On Batteries, Stop On Battery Mode"
So, when I run this I get: perl scripts/check_schtasks WARNING: scheduled task robocopy dir finished with error 3 Incidentally, robocopy finishes with error levels 1,2,3 even when it has run properly. It's its way of saying some files where copied. My problem is I cannot seem to get the %exclusions reference anywhere in the code. I know how to dereference it, but I do not know how to integrate that into the while loop for skipping the checks. Any help greatly appreciated

Replies are listed 'Best First'.
Re: dereferencing doubts
by Eliya (Vicar) on Dec 03, 2011 at 05:17 UTC
    but I do not know how to integrate that into the while loop for skipping the checks

    I think you want

    ... if ( $columns[6] != 0 ) { # skip exclusions if (ref (my $excl = $exclusions{$columns[1]} ) eq "ARRAY") + { # <--- next if grep $_ == $columns[6], @$excl; + # <--- } $lastresult_of{ $columns[1] } = $columns[6]; } ...

    presuming you specify the exclusions as

    $ ./941457.pl --exclude "robocopy dir"=3 --exclude "robocopy dir"=2 . +..
      This works! Thanks. Now I need some time to understand exactly what it does :-) Like I said, references and I are not (yet) best friends.
Re: dereferencing doubts
by Marshall (Canon) on Dec 03, 2011 at 00:12 UTC
    Forgive me but I am having a hard time understanding the Perl question here. Sounds like you should schedule a .bat file that deals with the error return values. There is only one "0" value, so that was picked as success (normally). If that doesn't describe what you have, then have a cli program (.bat file) deal with it and schedule that. Or am I missing something obvious?

    Oops:

    print "WARNING: scheduled task [$key] finished with error [$va +lue]\n";
    Perhaps this is where you put some special case exclusion code that ignore certain error codes($value) from certain programs($key)?