none
Powershell Script to Monitor Scheduled Tasks RRS feed

  • Question

  • I would like to write a script that will monitor all scheduled tasks and notify me via email when a scheduled job doesn't run or is not successful.  The problem is that I just started digging into Powershell and haven't gotten much past chapter one.  If anyone has done something like this or knows where I can get more information it would be much appreciated.  Thank you in advance.
    Wednesday, December 30, 2009 3:47 PM

Answers

All replies

  • The approach may be a bit different depending on whether you're looking at running this locally or remotely and are using PowerShell v1 versus v2.  Also, for what version of Windows...  If you could answer all of those questions, that will help...
    Wednesday, December 30, 2009 4:15 PM
    Moderator
  • Windows Server 2003 SP2 - Servers
    Windows XP Pro SP3 - Clients
    PowerShell v2
    Running remotely and monitoring scheduled tasks on severs only

    Wednesday, December 30, 2009 4:58 PM
  • Thanks.  You'll have to give me until likely next week to double-check on Server 2003.

    In the meantime, someone else might beat me to a solution though...
    Wednesday, December 30, 2009 7:35 PM
    Moderator
  • I just read through this:

    I tested the following, and it shows both AT commands and scheduled tasks on both win 7 and 2k3.

    $servername = "tome-mac"

    $schedule = new-object -com("Schedule.Service")
    $schedule.connect($servername)
    $tasks = $schedule.getfolder("\").gettasks(0)
    $tasks |select name, lasttaskresult, lastruntime

    Also, since you are using v2 you could use remoting and call schtasks and/or AT on each system, but I think the above will get the job done nicely.

    Side note: I noticed that the Schedule.service object would need to iterate through all of your task scheduler folders on win7/vista/2k8.  You shouldn't need to worry about it on 2k3/xp.
    Wednesday, December 30, 2009 7:36 PM
  • Hunh...  I either didn't know about a COM interface or forgot.

    The only risks with that approach:
    1. If you miss one run, you're getting the last error, but perhaps you're job has run more than once between you checking the last error code.
    2. That uses COM/DCOM, which is not firewall friendly.

    In any case, "Al", do let us know if Tome's solution is what you want/need.
    Wednesday, December 30, 2009 8:18 PM
    Moderator
  • Actually I found another script in Microsoft's script repository that I would rather use.  I can't get it to work however I am assuming because I am using v2 and the script was written for v1?  At any rate here is the code I am using and the error I get when trying to execute it.

    Code:

    http://gallery.technet.microsoft.com/ScriptCenter/en-us/8802ab28-6d0a-4795-8acb-e5a84a04606c

     

     



    Error:

    Cannot process argument because the value of argument "name" is invalid. Change the value of the "name" argument and run the operation again.

    At :line:46 char:20

    + $errors = Import-CSV <<<< ScheduleTaskMon.csv |

     

     

    Wednesday, December 30, 2009 8:50 PM
  • Import-csv is expecting a string argument, so you need to quote the filename:

    $errors = Import-CSV "ScheduleTaskMon.csv" |

    Wednesday, December 30, 2009 8:55 PM
  • Import-csv is expecting a string argument, so you need to quote the filename:

    $errors = Import-CSV "ScheduleTaskMon.csv" |


    Quotes aren't always required actually.
    Wednesday, December 30, 2009 9:51 PM
    Moderator
  • Yes I was thinking the same.  However, I tried quotes and it still fails. I tried shortening the name and it still fails.  I tried all small case and it still fails.  I tried all upper-case and it also fails.
    Wednesday, December 30, 2009 9:55 PM
  • Actually I found another script in Microsoft's script repository that I would rather use.  I can't get it to work however I am assuming because I am using v2 and the script was written for v1?  At any rate here is the code I am using and the error I get when trying to execute it.

    Code:

    http://gallery.technet.microsoft.com/ScriptCenter/en-us/8802ab28-6d0a-4795-8acb-e5a84a04606c

     

     



    Error:

    Cannot process argument because the value of argument "name" is invalid. Change the value of the "name" argument and run the operation again.

    At :line:46 char:20

    + $errors = Import-CSV <<<< ScheduleTaskMon.csv |

     

     


    Odd, no, this should work with v2.  I would recheck your script to make sure everything aligns properly.
    Wednesday, December 30, 2009 9:56 PM
    Moderator
  • I was reflecting on the first risk you mentioned.  It sent me on quite a mode of learning about how scheduled tasks works.  I found an entire world of logging built-in to the scheduled tasks.  I posted my findings here:


    To summarize for this thread there is a log file you can parse on each server/workstation to get the data you want.  If you're using win 2k8/Vista/Win7 there's an additional log that is very robust.  The base log is good, but it doesn't contain AT tasks.  The log file path can be found in this registry key: HKLM\Software\Microsoft\SchedulingAgent\LogPath

    My posting has a series of scripts I created for each method.

    Wednesday, December 30, 2009 10:07 PM
  • Seems like no matter what I do to the script I receive the following error(s):

    Import-Csv : Cannot process argument because the value of argument "name" is invalid. Change the value of the "name" ar
    gument and run the operation again.
    At C:\temp\TaskMonitor.ps1:46 char:21
    + $errors = Import-CSV <<<<  ScheduleTaskMon.csv | Where-Object {$_."Last Run Time" -lt $Dateminus -and $_."Schedule" -
    ne "Disabled" -and $_."Last Result" -ne 0}
        + CategoryInfo          : InvalidArgument: (:) [Import-Csv], PSArgumentException
        + FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.ImportCsvCommand

    Import-Csv : Cannot process argument because the value of argument "name" is invalid. Change the value of the "name" ar
    gument and run the operation again.
    At C:\temp\TaskMonitor.ps1:48 char:19
    + $body = Import-CSV <<<<  ScheduleTaskMon.csv | Where-Object {$_."Last Run Time" -lt $Dateminus -and $_."Schedule" -ne
     "Disabled" -and $_."Last Result" -ne 0} |
        + CategoryInfo          : InvalidArgument: (:) [Import-Csv], PSArgumentException
        + FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.ImportCsvCommand

    I haven't modified the format of the script.  I only made the necessary changes to make it work in my environment.  I have recreated the file from scratch and then made my modifications and once again I get the above error message(s).

    Wednesday, December 30, 2009 10:08 PM
  • Seems like no matter what I do to the script I receive the following error(s):


    You mentioned having v2, try to use the ISE.  Pay close attention to all of the coloring, maybe there's something off, even if just an extra character on a line.  The ISE "tokenizer" will parse your script and should clearly identify cmdlets and comments for example.

    First, just so you know you're not going crazy, and it is the script at fault, just do:
    PS > new-item -type file test.csv


        Directory: Microsoft.PowerShell.Core\FileSystem::C:\some_dir


    Mode           LastWriteTime       Length Name
    ----           -------------       ------ ----
    -a---    30/12/2009  7:08 PM            0 test.csv


    PS > import-csv test.csv
    PS >

    There's also a simple PowerShell script someone wrote that you can use to "verify" your script.  I'll see if I can find it again...
    Wednesday, December 30, 2009 11:10 PM
    Moderator
  • This is from Jason Shirk from the PowerShell team in a private mailing list, but I'm sure I can post it here since this is a public API:

    function tokenize
    {
      param($script)
    
      if (test-path $script -ea silentlycontinue)
      {
        $script = (get-content $script) -join "`n"
      }
      $errors = $null
      $tokens = [system.management.automation.psparser]::tokenize($script, [ref]$errors)
      $tokens, $errors
    }
    Copy and paste the above into PowerShell, then simply do:
    PS> tokenize your_powershell_script.ps1

    It will return errors if it can parse the entire script...

    You may want to change that second to last line to simply this before trying:
    $errors
    Wednesday, December 30, 2009 11:20 PM
    Moderator
  • Marco,

    I have tried all of your suggestions.  In the ISE everything looks like it is in the correct places.  Using the function you provided I receive no errors.  Does the script run for you?  I am completely stumped at this point.  Thanks for all of your input.

    Al
    Thursday, December 31, 2009 3:52 PM
  • The script ran for me.  Are the csv files getting created?  If you have no scheduled tasks on your system it won't create the csvs.... Is that your problem?

    What if you run it in two sections?  Everything before the import (everything that creates the files)... then run the second half of it.  Maybe something is still open?

    It's weird b/c the error you are getting doesn't sound like it would be either of my suggestions....

    Also... if you have the csv file in place try running just the following by itself.  Make sure you type it in... don't copy/paste:
    $errors = Import-Csv ScheduleTaskMon.csv | Where-Object {$_."Last Run Time" -lt $Dateminus -and $_."Schedule" -ne "Disabled" -and $_."Last Result" -ne 0}

    does it still return an error?  If so, is it the same error?  Also what are the contents of the csv file?

    Thursday, December 31, 2009 10:38 PM
  • Tome,

    Thanks for your suggestion.  The CSV files are created and all the expected information is in the file.  I did as you said and run the program in two parts.  The first section runs without a hitch.  The second part throws the same error as we have been talking about.  When I run the section mentioned by itself it throws the same error once again.  I believe there has to be something wrong with my operating environment that is causing the issue.  On Monday I am going to throw this into the test network and see what happens.  Thanks for all the input and Happy New Year.

    Al
    Saturday, January 2, 2010 3:22 PM
  • Now, this could spit out a whole lot of data, but try something like this:
    PS>trace-command -name parameter* -pshost -exp {import-csv foo.csv}

    You'll need to trip down as much as possible, for example, does just doing this give the same error?
    PS>$errors = Import-Csv ScheduleTaskMon.csv
    Saturday, January 2, 2010 5:00 PM
    Moderator
  • Are you sure the problem is not in your .csv?

    Does running "Import-Csv ScheduleTaskMon.csv" from a ps session produce that error?

    Saturday, January 2, 2010 5:25 PM
  • It has to be problems with the csv file.  I am capable of importing any other csv file with no problems.  No matter how I run this command I get the same errors.

    Monday, January 4, 2010 11:04 PM
  • Try a get-content on the .csv file and see if you can determine the problem from that.
    Monday, January 4, 2010 11:08 PM
  • Have you tried deleting the CSV, and then running the create part again?
    Monday, January 4, 2010 11:38 PM
  • Success!  Thank you all for your valuable input.  Looking into the CSV file I was able to determine that the schtasks export wasn't exporting the details so I could read them with the script.  I imported the data in using comma's as the delimiter and viola the script worked!  Now I will just need to figure out how I can get the script to grab the data and manipulate it without needing to manually modify the .csv file.  At any rate I think I am on the right track and reall appreciate all the help.

    Al.

    • Proposed as answer by Matt F Warren Tuesday, January 5, 2010 3:21 PM
    Monday, January 4, 2010 11:53 PM
  • seems like the csv is adding a blank line header that throws off import-Csv.

    here's my work around:

    ...
    foreach ($svr in $Servers){
                    # EXAMPLE: schtasks /query /FO CSV /V > ScheduleTaskMon.log
                    If ($servercount -gt 0) {
                                    #write-host schtasks /query /s $svr /FO CSV /NH /v >> ScheduleTaskMon.csv
                                    schtasks /query /s $svr /FO CSV /NH /v >> ScheduleTaskMon.out
                                    }
                    Else {
                                    #write-host schtasks /query /s $svr /FO CSV /v > ScheduleTaskMon.csv
                                    schtasks /query /s $svr /FO CSV /v > ScheduleTaskMon.out
                                    }
                   
                    $servercount++
    }
     
    cat ScheduleTaskMon.out | where {$_ -notmatch "^$" } > ScheduleTaskMon.csv


    ....
    Tuesday, January 5, 2010 3:23 PM
  • Since you're basically just filtering out a null string, this should work just as well:

    cat ScheduleTaskMon.out | where {$_} > ScheduleTaskMon.csv
    Tuesday, January 5, 2010 3:28 PM
  • Both suggestions work like a charm!!  Thanks a lot.  I learned a lot during this process and I really appreciate your willingness to help and your patience!

    Al

    Tuesday, January 5, 2010 3:53 PM
  • could get rid of the temporary file...

    If ($servercount -gt 0) {
                                    #write-host schtasks /query /s $svr /FO CSV /NH /v >> ScheduleTaskMon.csv
                                    schtasks /query /s $svr /FO CSV /NH /v | where {$_ -notmatch "^$" } >> ScheduleTaskMon.csv
                                    }
                    Else {
                                    #write-host schtasks /query /s $svr /FO CSV /v > ScheduleTaskMon.csv
                                    schtasks /query /s $svr /FO CSV /v | where  {$_ -notmatch "^$" } > ScheduleTaskMon.csv
                                    }
    Tuesday, January 5, 2010 3:55 PM