Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Win32 Task Scheduler Monitor

by LovelyGreeting (Novice)
on May 31, 2002 at 05:50 UTC ( [id://170633]=perlquestion: print w/replies, xml ) Need Help??

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

I'm looking for Perl solution to monitor execution status of Win32 task scheduler, like 'status' and 'last result'. It seems there are two solutions: Win32::Lanman and Win32::AdminMisc. I have downloaded the code. It runs silently, nothing back. Codes listed for your reference. Any feedback will be greatly appreciated!
#============================= # Win32::AdminMisc #============================= use win32::adminmisc; $Jobs = Win32::AdminMisc::ScheduleList("\\\\server01", \%Jobs); print "==>".%Jobs."\n"; foreach $Number (keys(%Jobs)){ print "Job $Number is $Jobs{$Number}->{Command}\n"; }
#============================= # Win32::Lanman #============================= use Win32::Lanman; use Win32::NetAdmin; @ARGV[0]; if (@ARGV[0] eq ""){print "\n\nSyntax\n\n\ttasks.pl servername\n\ttask +s.pl all\n\n"; exit 1;} if ("\U@ARGV[0]\E" eq "ALL"){&getservers;} else {@servers = ("@ARGV[0] +");} $output = "C:\\temp\\task.txt"; open(OUTPUT, ">$output") || die "Can't open $output"; %DOW = ( 0,'', 1,'Monday', 2,'Tuesday', 4,'Wednesday', 8,'Thursday', 16,'Friday', 32,'Saturday', 64,'Sunday' ); %DOM = ( 0,'', 1,'1', 2,'2', 4,'3', 8,'4', 16,'5', 32,'6', 64,'7', 128,'8', 256,'9', 512,'10', 1024,'11', 2048,'12', 4096,'13', 8192,'14', 16384,'15', 32768,'16', 65536,'17', 131072,'18', 262144,'19', 524288,'20', 1048576,'21', 2097152,'22', 4194304,'23', 8388608,'24', 16777216,'25', 33554432,'26', 67108864,'27', 134217728,'28', 268435456,'29', 536870912,'30', 1073741824,'31' ); %FLAG = ( 1,'Reoccuring job - Interactive', 3,'Reoccuring job - Interactive - Error when last run', 4,'One time job - Will run today - Interactive', 5,'Reoccuring job - Will run today - Interactive', 17,'Reoccuring job - Non-Interactive', 19,'Reoccuring job - Not Interactive - Error when last run', 20,'One time job - Will run today - Not Interactive', 21,'Reoccuring job - Will run today - Not Interactive' ); foreach $server (@servers) { print "querying $server\n"; if(!Win32::Lanman::NetScheduleJobEnum("\\\\$server", \@jobs)) { print "\n\nUnable to read scheduled jobs from $server\n\n"; next; } print "==>".@jobs."\n"; foreach $job (@jobs) { print OUTPUT "server = $server\n"; @keys = keys %$job; $job->{'daysofweek'} = $DOW{$job->{'daysofweek'}}; $job->{'daysofmonth'} = $DOM{$job->{'daysofmonth'}}; $job->{'flags'} = $FLAG{$job->{'flags'}}; $runtime = ${$job}{'jobtime'}/1000; $hour = sprintf("%02d", (int ($runtime / 3600))); $min = sprintf("%02d", (int ((($runtime - ($hour * 3600)) / 60 +)))); $job->{'jobtime'} = "$hour:$min"; foreach $key (@keys) { print OUTPUT "$key = ${$job}{$key}\n" if (${$job}{$key} ne + ""); } print OUTPUT "\n---------------------------------------------- +----------\n\n"; } } print "==>".@jobs."\n"; close OUTPUT; sub getservers { my (@servers1, @servers2, @servers3); print "\nLooking up server names\n\n"; my $domain = Win32::DomainName; Win32::NetAdmin::GetDomainController("", $domain, $PDC) || print " +Unable to obtain the PDC name for $domain."; Win32::NetAdmin::GetServers($pdc, $domain, 0x00000008, \@servers1) + || print "Unable to read NetBios 0008."; Win32::NetAdmin::GetServers($pdc, $domain, 0x00000010, \@servers2) + || print "Unable to read NetBios 0010."; Win32::NetAdmin::GetServers($pdc, $domain, 0x00008000, \@servers3) + || print "Unable to read NetBios 8000."; @servers = (@servers1, @servers2, @servers3); }

Replies are listed 'Best First'.
Re: Win32 Task Scheduler Monitor
by Courage (Parson) on May 31, 2002 at 16:32 UTC
    two obvious things:
    - use Win32::AdminMisc; #and not win32::adminmisc; remember, that package names are case sensitive! Otherwise you'll face unexpected behaviour, such as not-calling 'import' package function at proper time.
    - use strict; # will have a chance to see report about above mentioned problems

    (I did similar things about a year ago, and will try to look deeper into your problem if my obvious advices will not work.)

    Courage, the Cowardly Dog.

      Thank you, Courage. Attached modified code, it still got 0 task list back. And here is my configuration information for your reference:
      OS:Win2000 Professional Perl:ActiveState 5.005_02 Win32::AdminMisc:NAME="Win32-AdminMisc",VERSION="0,2000,07,08"
      use strict; use Win32::AdminMisc; my $server="\\\\twjimmywang"; my %JobInfo; my $Day; my @DOM; my %Jobs; my $Number; if (Win32::AdminMisc::ScheduleGet($server, 3, \%JobInfo)){ foreach $Day (1..31){ push(@DOM, $Day) if ($JobInfo{DOM} & 2**$Day); } print "This job will run on the following days of the month:\n"; print join(", ", @DOM); } print "==>".%JobInfo."\n"; Win32::AdminMisc::ScheduleList($server, \%Jobs); print "==>".%Jobs."\n"; foreach $Number (keys(%Jobs)){ print "Job $Number is $Jobs{$Number}->{Command}\n"; }
        well, my luck here is probably better that yours, because your latest unmodified script works with some non-zero results, after I added a task. Look:
        D:\>at 20:20 /interactive /every:5 calc Added a new job with job ID = 2 D:\Personal\perl\admin\tst>perl -w am.pl ==>0 ==>1/8 Job 2 is calc
        1/8 is hash in scalar context, you ignore "8" and see that you have one single key in that hash.

        Slightly reorganize code and see that we've got what we searched for:

        use strict; use Win32::AdminMisc; my $server="\\\\serverserversevverv"; my %JobInfo; my $Day; my @DOM; my %Jobs; my $Number; Win32::AdminMisc::ScheduleList($server, \%Jobs); print "==>".%Jobs."\n"; foreach $Number (keys(%Jobs)){ print "Job $Number is $Jobs{$Number}->{Command}\n"; if (Win32::AdminMisc::ScheduleGet($server, $Number, \%JobInfo)){ foreach $Day (1..31){ push(@DOM, $Day) if ($JobInfo{DOM} & 2**$Day); } print "This job will run on the following days of the month:\n +"; print join(", ", @DOM); } }
        the output is not that bad in my case:
        D:\Personal\perl\admin\tst>perl -w am.pl ==>2/8 Job 2 is calc This job will run on the following days of the month: 4Job 3 is calc This job will run on the following days of the month: 4, 18

        let me know if you need more details.

        Courage, the Cowardly Dog.
        PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.

Re: Win32 Task Scheduler Monitor
by Courage (Parson) on Jun 05, 2002 at 16:01 UTC
    okay, there is much shorter to write, but longer to read docs way, using WMI (Windows Management Instrumentation), MSDN describes details, code and results are as following (just few lines of code! i did not expected to have such short program to do the trick...) :
    use Win32::OLE 'in'; $objcoll = Win32::OLE->GetObject("WinMgmts://servername")->InstancesOf +("Win32_ScheduledJob"); my @x = qw/ Caption Command DaysOfMonth DaysOfWeek Description ElapsedTime Insta +llDate InteractWithDesktop JobId JobStatus Name Notify Owner Priority RunRe +peatedly StartTime Status TimeSubmitted UntilTime /; for $adsobj (in $objcoll) { print ++$i,".===\n",join '', map {" $_:".($adsobj->{$_}||"")."\n"} +@x; } ===== 1.=== Caption: Command:calc DaysOfMonth:16 DaysOfWeek: Description: ElapsedTime: InstallDate: InteractWithDesktop:1 JobId:2 JobStatus:Success Name: Notify: Owner: Priority: RunRepeatedly:1 StartTime:********202000.000000+240 Status: TimeSubmitted: UntilTime: 2.=== Caption: Command:calc DaysOfMonth:262144 DaysOfWeek: Description: ElapsedTime: InstallDate: InteractWithDesktop:1 JobId:3 JobStatus:Success Name: Notify: Owner: Priority: RunRepeatedly:1 StartTime:********202000.000000+240 Status: TimeSubmitted: UntilTime:
    Note that GetObject("WinMgmts://servername") becomes GetObject("WinMgmts:") if you're working locally

    Courage, the Cowardly Dog.
    PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.

      Dear Courage, I wolud love to appreciate for all you have done. After tried the WMI approach, it can get all AT instances, but can't see any instance created by Task Scheduler UI program. However, your MSDN research lights me up. After several search in MSDN, I found COM objects called Task Scheduler API and one sample C++ code. It works on instances created by Task Scheduler UI Program. Then, I found another Perl extension Win32-TaskScheduler, created by Umberto Nicoletti. You can find it at http://taskscheduler.sourceforge.net. I'm not familiar with Perl, COM, OLE, but still tried to build a simple example querying the status of remote machine's Task Scheduler instances. Attached for your reference: Thank you very much!!
      use strict; use Win32::TaskScheduler; (my $Machine = shift @ARGV || "" ) =~ s/^[\\\/]+//; my $scheduler; my @jobs; my $job; my $jobname; my $account; my $APname; my $parameter; my $workdir; my $triggerCnt; my $idx; my %trigger; my $key; my $trigType; my $flags; my $status; my $exitcode; $scheduler = Win32::TaskScheduler->New(); if ( $Machine ) { $scheduler->SetTargetComputer("\\\\".$Machine) or die("Failed: Set + Server Machine:".$Machine."\n"); } @jobs = $scheduler->Enum(); foreach $job ( @jobs ) { $jobname = substr($job,0,length($job)-4); $scheduler->Activate($jobname) or die("Failed: Activate".$job." [" +.$jobname."]\n"); print "==>".$job." [".$jobname."]\n"; $APname = $scheduler->GetApplicationName(); if ( $APname ) {print "\tAPname:".$APname."\n";} $parameter = $scheduler->GetParameters(); if ( $parameter ) {print "\tParameter:".$parameter."\n";} $workdir = $scheduler->GetWorkingDirectory(); if ( $workdir ) {print "\tWorkDir:".$workdir."\n";} $account = $scheduler->GetAccountInformation(); if ( $account ) {print "\tAccount:".$account."\n";} $scheduler->GetExitCode($exitcode); print "\tExitCode:".$exitcode."\n"; $scheduler->GetStatus($status); if ( $status == 267008 ) { #Ready print "\tStatus:ready\n"; } elsif ( $status == 267009 ) { #Runnig print "\tStatus:RUNNING\n"; } elsif ( $status == 267010 ) { #Not Scheduled print "\tStatus:Not Scheduled\n"; } else { print "\tStatus:UNKNOWN\n"; } $flags = $scheduler->GetFlags(); if ( $flags ) {print "\tFlags:".$flags."\n";} $triggerCnt = $scheduler->GetTriggerCount(); if ( $triggerCnt > 0 ) { for ( $idx = 0; $idx < $triggerCnt; $idx++ ) { print "\tTrigger $idx:\n"; $scheduler->GetTrigger($idx,\%trigger); foreach $key (keys %trigger) { if ( $key eq "TriggerType" ) { $trigType = $trigger{$key}; if ( $trigType == $scheduler->TASK_TIME_TRIGGER_ON +CE ) { print "\t\t$key=ONCE\n"; } elsif ( $trigType == $scheduler->TASK_TIME_TRIGGER +_DAILY ) { print "\t\t$key=DAILY\n"; } elsif ( $trigType == $scheduler->TASK_TIME_TRIGGER +_WEEKLY ) { print "\t\t$key=WEEKLY\n"; } elsif ( $trigType == $scheduler->TASK_TIME_TRIGGER +_MONTHLYDATE ) { print "\t\t$key=MONTHLY_DATE\n"; } elsif ( $trigType == $scheduler->TASK_TIME_TRIGGER +_MONTHLYDOW ) { print "\t\t$key=MONTHLY_DOW\n"; } elsif ( $trigType == $scheduler->TASK_EVENT_TRIGGE +R_ON_IDLE ) { print "\t\t$key=ON_IDLE\n"; } elsif ( $trigType == $scheduler->TASK_EVENT_TRIGGE +R_AT_SYSTEMSTART ) { print "\t\t$key=AT_SYSTEMSTART\n"; } elsif ( $trigType == $scheduler->TASK_EVENT_TRIGGE +R_AT_LOGON ) { print "\t\t$key=AT_LOGON\n"; } else { print "\t\t$key=".$trigger{$key}."\n"; } } else { print "\t\t$key=".$trigger{$key}."\n"; } } } } } $scheduler->End(); Command Line: ************* perl -w sched.pl twjimmywang Sample Output: ************** ==>NetLinkMonitor.job [NetLinkMonitor] APname:D:\MRTG\NetLinkMonitor\NetUp.exe WorkDir:D:\MRTG\NetLinkMonitor Account:TW01\adm ExitCode:0 Status:ready Flags:192 Trigger 0: MinutesInterval=0 Flags=0 StartMinute=0 EndMonth=0 BeginDay=29 RandomMinutesInterval=0 BeginMonth=4 TriggerType=AT_SYSTEMSTART EndYear=0 StartHour=0 MinutesDuration=0 BeginYear=2002 EndDay=0 ==>Mrtg.job [Mrtg] APname:D:\MRTG\CFG\Mrtg.bat WorkDir:D:\MRTG\CFG Account:TW01\adm ExitCode:0 Status:ready Flags:192 Trigger 0: MinutesInterval=0 Flags=0 StartMinute=0 EndMonth=0 BeginDay=14 RandomMinutesInterval=0 BeginMonth=3 TriggerType=AT_SYSTEMSTART EndYear=0 StartHour=0 MinutesDuration=0 BeginYear=2002 EndDay=0
        You're right. I forgot to try creating tasks via GUI.
        Anyway, it was good exercise for me to try.

        Best wishes,
        Courage, the Cowardly Dog.
        PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://170633]
Approved by virtualsue
Front-paged by RhetTbull
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (8)
As of 2024-03-28 09:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found