Use PowerShell to Manage Scheduled Tasks in SharePoint

ScriptingGuy1

Summary: Learn how to use Windows PowerShell to manage scheduled tasks for your SharePoint Server.

Microsoft Scripting Guy, Ed Wilson, is here. One of the really cool things about being the Microsoft Scripting Guy is getting to meet lots of smart people who love Windows PowerShell as much as I do. I feel as if Jonathan Tyler is one of my oldest friends; but as of now, I have not met him in real life. After months of hard work, we finally got the details worked out, and I am going to speak at his company in a few months when the Scripting Wife and I head to Raleigh, North Carolina for the SQL Solstice conference. I am looking forward to meeting Jonathan—it promises to be one of the highlights of a very memorable trip.

Anyway…I digress a bit.

I have been talking to Jonathan for several years as I have answered various questions from him via the scripter@microsoft.com email alias. After a while, I actually gave him my “real” email address. I noticed that he also lives in North Carolina, we chatted, and the rest is Scripting Guy history. And today, we have our first of what I imagine will be many blogs written by Jonathan. WOO HOO!!!

Photo of Jonathan Tyler

Jonathan Tyler is a senior software engineer employed by one of the world’s leading providers of commercial transport solutions. Jonathan has been in the IT industry since 1997. He currently supports the global SharePoint farm for the company’s Internet, extranet, and intranet solutions. Since working as a consultant, Jonathan started working with VBScript to automate tasks. He has done work in Visual Basic, C#, and Windows PowerShell. Check out his blog, PowerShell Reflections.

Scheduled Task Reporting with Windows PowerShell

As a SharePoint administrator, there are many times that we have scheduled tasks that run on the system for various reasons. Perhaps I need a security report, or a list of newly added items, or maybe I need to get a list of items that are no longer used on any of the pages. With approximately 25 web applications in one farm, it is important to keep track of these tasks to make sure they stay running.

I had not played around with it before, but I ran across the Schtasks.exe command, which will enumerate all of the scheduled tasks on a system. You can even specify a remote system to query. After messing around a bit, I found the formatting switch and saw that I could export all the information about a task as CSV-formatted data. Anyone who works with Windows PowerShell for any length of time knows that PowerShell eats CSV files for breakfast. Let’s see how to make this work!

My first thought would be that I could simply export this CSV information to a text file and then have PowerShell import the text file (Import-CSV) to begin my work. That seemed a little messy to me. A quick look with the Get-Command cmdlet showed what I need:

Image of command output

The ConvertFrom-CSV cmdlet seems to fit the bill. After looking at some of the options for the Schtasks command, I settled on the following command line to get my information.

SCHTASKS /QUERY /s Server01 /FO csv /V

This command will query Server01 for all (Verbose: /v) scheduled tasks and format (/FO csv) the data as a CSV. So that I can manipulate the information a bit more, I need to capture this into a variable.

$tasks = & SCHTASKS /QUERY /s Server01 /FO csv /v | ConvertFrom-CSV

After I get the data into the variable, I examine it to see what I have to work with. This is where I notice a problem. I have a couple of properties, Next Run Time and Last Run Time, that don’t always have the information I expect. Normally, these properties would be expected to have a date/time value, but because this is a scheduled task, the task may not have ever run or may never run again. In that case, the Schtasks.exe command reports “Never.” I don’t know about you, but I find that Windows PowerShell has a hard time trying to sort this information with a date/time value. So, I set about trying to make this work.

My solution is to go through each entry, test to see if the Next Run Time and Last Run Time properties are actually a date/time value. If they are, I convert the property to a DateTime object. If not, I reset the property to the DateTime.MaxValue or DateTime.MinValue, respectively. Now, I can sort the values to get what I need.

$tasks |Foreach-Object {

    If ($_.”Last Run Time” –as [datetime])

    {

        $_.”Last Run Time” = [datetime]$_.”Last Run Time”

    }

    Else

   {

        $_.”Last Run Time” = [datetime]::MinValue

    }

    If ($_.”Next Run Time” –as [datetime])

    {

       $_.”Next Run Time” = [datetime]$_.”Next Run Time”

    }

    Else

    {

       $_.”Next Run Time” = [datetime]::MaxValue

    }

}

Now that I have my DateTime values set properly, I can find the information that I am really interested in. The original purpose of my script is to tell me anything that ran within the past 24 hours that did not succeed for any reason.

In the script source, you will notice that I also check to see that the $tasks variable is populated. If the computer you query does not have any scheduled tasks to report, there is no need to proceed through the rest of the code. The Schtasks command will report a string that indicates there are no scheduled tasks on the system. When you try to push that through the ConvertFrom-CSV cmdlet, it returns a $null value.

To get tasks that ran within the past 24 hours, I will use the New-TimeSpan cmdlet. I can feed the Last Run Time property from the $tasks variable as the start time and then specify that I want the result to be in “days.” I also want to make sure that I get any tasks that have a Last Result value other than “0.” Here is what that code looks like.

$TasksInError = $tasks | Where-Object {

    ((New-TimeSpan –Start $_.”Last Run Time”).Days –le $runPeriod) –and

    ($_.”Last Result” –ne “0”)} | `

    Sort-Object “Last Run Time” –Descending | `

    ConvertTo-HTML –property TaskName, “Next Run Time”, “Last Run Time”, Status, “Last Result” –Fragment | Out-String

In the last part of this command, I have chosen to output my data as an HTML fragment. I decided that I want to send the information to my colleagues and myself so that we can jump on a problem as soon as possible. To make the formatting easier, I decided to use the HTML formatting and make the body of the email message as HTML as well. However, I don’t want to send an empty email, so to make that work, I simply check to make sure that I have data in the $TasksInError variable before trying to send the email.

If ($TasksInError)

{

    Send-MailMessage –Body $TasksInError –BodyAsHTML –From myscript.donotreply@mydomain.com –SmtpServer mymailserver.mydomain.com –Subject “Scheduled Task Report – $ComputerName” –To myaddress@mydomain.com

}

I have set this script up as an Advanced Script/Function which means that I can pipe multiple computer names into the script to run against. This can be set up on a management machine to query multiple machines. Following is the complete script source. Because this script is rather long, I have uploaded it to the Scripting Guys Script Repository so you can easily get the script without worrying about copying HTML crud from the web page.

Get-ScheduledTask.ps1

<#

      .SYNOPSIS

            Gathers scheduled tasks that ran within past 24 hours and e-mails

            a report of failed tasks.

 

      .DESCRIPTION

            This script calls the SCHTASKS.EXE command to gather all scheduled task

            information.  It returns all tasks from the past 24 hours that do not

            have a “Last Result” of “0”.

 

      .PARAMETER  ComputerName

            Specifies the computer to query for scheduled tasks.

 

      .PARAMETER  runPeriod

            Specifies the number of days to look back for scheduled tasks

           

      .EXAMPLE

            PS C:\> .\Get-ScheduledTasks.ps1 -ComputerName Server01

           

            DESCRIPTION

            ———–

            This command will connect to Server01 and gather the requested Scheduled

            Tasks.

 

      .EXAMPLE

            PS C:\> .\Get-ScheduledTasks.ps1 -ComputerName Server01 -runPeriod 5

           

            DESCRIPTION

            ———–

            This command will connect to Server01 and gather the requested Scheduled

            Tasks from the past five (5) days.

           

      .INPUTS

            System.String,System.Int32

 

      .OUTPUTS

            Nothing

 

      .NOTES

            This script is designed to be run as a scheduled task.

 

      .LINK

            about_functions_advanced

 

      .LINK

            about_comment_based_help

 

#>

 

[CmdletBinding()]

Param (

            [Parameter(ValueFromPipeline=$true)]

            [string]

            $ComputerName = $env:COMPUTERNAME

            ,

            [int]

            $runPeriod = 1

            )

           

PROCESS {

      $tasks = & schtasks /query /s $ComputerName /fo csv /v | ConvertFrom-Csv

           

      if ($tasks)

      {

            $tasks | ForEach-Object {

                  if ($_.“Last Run Time” -as [datetime])

                  {

                        $_.“Last Run Time” = [dateTime]$_.“Last Run Time”

                  }

                  else

                  {

                        $_.“Last Run Time” = [datetime]::MinValue

                  }

                  if ($_.“Next Run Time” -as [datetime])

                  {

                        $_.“Next Run Time” = [dateTime]$_.“Next Run Time”

                  }

                  else

                  {

                        $_.“Next Run Time” = [datetime]::MaxValue

                  }

                 

            }

                 

            $TasksInError = $tasks | Where-Object {

                  ((New-TimeSpan -Start $_.“Last Run Time”).Days -le $runPeriod) -and

                  ($_.“Last Result” -ne “0”)} | `

                  Sort-Object “Last Run Time” -Descending | `

                  ConvertTo-HTML -property TaskName, “Next Run Time”, “Last Run Time”, Status, “Last Result” -Fragment | out-string

 

            if ($TasksInError)

            {

                  Send-MailMessage -Body $TasksInError -BodyAsHtml -From donotreply@mydomain.com -SmtpServer mysmtpserver.mydomain.com -Subject “Scheduled Tasks Report – $ComputerName” -To myaddress@mydomain.com

            }

      }

}

I want to thank Jonathan for providing an excellent blog and for sharing his script with us. Join me tomorrow for more Windows PowerShell goodness.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

0 comments

Discussion is closed.

Feedback usabilla icon