Using Scheduled Tasks and Scheduled Jobs in PowerShell

Doctor Scripto

Summary: Learn about using scheduled tasks and scheduled jobs in Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. Today Dave Bishop, senior technical writer on the Windows Server team, and June Blender, senior programming writer on the Windows Azure Active Directory team, investigate scheduled tasks and scheduled jobs in Windows PowerShell. And now, here’s June…

Windows PowerShell 3.0 introduced dozens of new modules and thousands of new cmdlets. Much of this was the work of Microsoft teams building Windows PowerShell interfaces for Windows tools. In the mix were two modules that sound like they do almost the same thing: PSScheduledJob and ScheduledTasks. They’re actually different approaches to solving the same problem, and they share some common technology. The best one to use depends on what you’re trying to schedule.

Dave will start us out with a review of scheduled tasks, and I’ll jump in with some info about scheduled jobs. Be sure to read the official help topics for both modules:  PSScheduledJob Module and Scheduled Task Cmdlets in Windows PowerShell.

Scheduled tasks

Scheduled tasks are much more general than scheduled jobs. The Task Scheduler graphical UI program (TaskSchd.msc), and its command-line equivalent (SchTasks.exe) have been part of Windows since some of the earliest days of the operating system. They enable you to schedule the running of almost any program or process, in any security context, triggered by a timer or a wide variety of system events.

Scheduled tasks are a core infrastructure component of Windows and, they are used extensively by many Windows components and other products that run on Windows. Although SchTasks.exe enables you to fully interact with your tasks from a command line, it is not object-oriented, as are the ScheduledTask module’s cmdlets. Each cmdlet consumes, processes, or returns an object, unlike the older command-line tools that generally consume and emit only text strings.

The only thing that is really missing from a scheduled task is the native ability to capture and manipulate the output of the task. Because a scheduled task can run almost anything that is runnable on a Windows computer, it’s not possible to anticipate and capture the output of a scheduled task. According to Windows PowerShell MVP, Karl Prosser, the output of scheduled tasks goes to “the same place where your clothes dryer puts your lost socks.”

Because a scheduled job is always Windows PowerShell script, even if that script is used to run a non-Windows PowerShell program, it is possible for the system to capture that predictable output: the Windows PowerShell object that is returned at the end of the script block. However, that’s a relatively minor limitation because there is nothing to prevent your scheduled task from saving its output to disk in some form that you can later retrieve and manipulate.

A scheduled task consists of:

  • An action that specifies the program to be run.
  • A trigger that defines the time or system event that determines when the program is to be run.
  • A principal that identifies the context to use to execute an action.
  • Additional settings that further configure the task and control how the action is run.

You can find the cmdlets that work with scheduled tasks in the ScheduledTasks module that is included with Windows 8 and Windows Server 2012. To see the complete list of cmdlets on your system, run the command:

Get-Command –Module ScheduledTasks

Hint  You can also abbreviate that to gcm –m ScheduledTasks. To see the syntax and description for any cmdlet, run Get-Help CmdletName. You can see more details and examples if you use the -Detailed, -Examples, or -Full parameters. The cmdlets let you define, view, and modify scheduled task objects and all the component objects that make up a scheduled task. For example, the commands below create a scheduled task that launches Notepad as an Administrator at 5:00 AM.  I know, I know, unbelievably useful.

$ST_A = New-ScheduledTaskAction –Execute “c:\windows\system32\notepad.exe”
$ST_T = New-ScheduledTaskTrigger -Once -At 5am
Register-ScheduledTask –TaskName “Notepad As Admin at 5AM” -Action $ST_A –Trigger $ST_T –User “Contoso\Administrator”

Managing failover clusters with scheduled tasks

One other important feature about scheduled tasks that is not shared by scheduled jobs is the ability to deal with the specifics of tasks on a failover cluster server. Tasks on a cluster server can be specified to run as follows:

  • On any node: There is only one instance of the task, and the task triggers on only one node. After it is triggered, the other nodes recognize it as having been triggered, and they do not attempt to run it on the other nodes. A good example is a task that runs a report on the cluster. You only want it run once, and you don’t care which node runs the task.
  • On a specific resource: There is only one instance of the task, and it is bound to a resource. It can only trigger on the same node as the bound resource. If the resource fails over to another node, so does the task. A good example of this type is a disk defragmenter task. You bind the task to the Disk resource, so it will always run on the node that currently owns the disk.
  • On the cluster: There is one instance of the task on each node of the cluster. When a trigger condition is met, the action is run on all nodes that are present in the cluster and meet the trigger condition. An example of this is a task that opens a tool whenever you sign in.

These capabilities add some power to scheduled tasks in the failover cluster environment. There are no cluster-specific options for scheduled jobs. Now let’s switch over to June for a look at some other interesting intersections of these two technologies.

Managing scheduled jobs in task scheduler

Thanks, Dave! As Dave explained, scheduled tasks are native to Windows. Similarly, scheduled jobs are native to Windows PowerShell. They’re a hybrid of background jobs and scheduled tasks. Scheduled jobs added the ability to schedule a background job, just like you schedule a task.

Well, almost.

In addition to using the job and scheduled job cmdlets, you can use the Task Scheduler UI and scheduled task cmdlets to manage scheduled jobs, but you can’t use the job or scheduled job cmdlets to manage scheduled tasks. Scheduled jobs and scheduled tasks export their definitions as .xml files, but the files contain different data and use a different XML schemas, so they’re not fully compatible.

There are a few similarities. The scheduling features of scheduled jobs are modeled on scheduled tasks. The design team tried to enable the same job options that you find in Task Scheduler, and they used the same terminology. To start a scheduled job (or a scheduled task), you use a “trigger.” The commands that run are called “actions.” And they tried to tie scheduled jobs to Task Scheduler as much as they could.

To create a scheduled job, you have use the scheduled job cmdlets. (Anything created in Task Scheduler is a scheduled task, even if it’s in the ScheduledJobs path.) But after the scheduled job is created, you can view and manage it in Task Scheduler. Scheduled jobs are located in the Microsoft\Windows\PowerShell\ScheduledJobs path in Task Scheduler. Here’s a screenshot of my Windows PowerShell console superimposed on Task Scheduler.

Image of menu

If you select a scheduled job in Task Scheduler, you can see the job triggers on the Triggers tab, and you can see the scheduled job options on the General tab and on the Conditions tab. Job instances that have run are shown on the History tab.

Image of menu

If you change a scheduled job setting in Task Scheduler, it is effective for all future instances of the scheduled job. For example, if you change the trigger time, you can see the new time in Windows PowerShell. The change affects all future instances of the job. For example, if I use Task Scheduler to change the trigger time from 10:20 AM to 9:20 AM, I can see it in Windows PowerShell, and it’s effective—future instances run at 9:20 AM.

PS C:\ps-test> Get-ScheduledJob Update-MyHelp | Get-JobTrigger

Id         Frequency       Time                   DaysOfWeek              Enabled

—         ———       —-                   ———-              ——-

1          Daily           10/17/2012             9:20:00 AM              True

You can even change a value on the Settings tab to add a setting that isn’t available in the scheduled job cmdlets. My favorite value is Run the task as soon as possible if a scheduled start is missed.

Features of scheduled jobs

There are some cool things in scheduled jobs that aren’t available in scheduled tasks. The job instances that the scheduled jobs start are Windows PowerShell background jobs that you can view and manage by using the Job cmdlets. The best part of a scheduled job is that all results of all job instances are saved at the following location, and they are available to you at any time:

$home\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs\<jobName>\Output

To get them, run:

PS C:\ps-test> dir $home\appdata\local\Microsoft\Windows\PowerShell\ScheduledJobs\Update-MyHelp

    Directory: $home\appdata\local\Microsoft\Windows\PowerShell\ScheduledJobs\Update-MyHelp

Mode                LastWriteTime     Length Name

—-                ————-     —— —-

d—-        10/14/2013  10:20 AM            Output

-a—        10/15/2013   2:50 PM       7000 ScheduledJobDefinition.xml

The scheduled job action (the command that runs when the job is triggered) can be Windows PowerShell commands in a script block, Windows PowerShell scripts (identified by file path), or any executable file on the machine.

Hey, Dave, can I use SchTasks.exe or the scheduled task cmdlets on my scheduled job?

Managing scheduled jobs with ScheduledTasks and Schtasks.exe

You sure can, June! You can use the UI, SchTasks.exe, or the cmdlets in the ScheduledTasks module to modify the triggers and several other settings of the job. The biggest thing to notice is that running the script is automatically translated in the task to run PowerShell.exe with the hidden parameters –NoLogo, –NonInteractive, and –WindowStyle, and with an the following embedded Windows PowerShell script:

Import-Module PSScheduledJob
$jobDef = [Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]::LoadFromStore(‘JobName‘, ‘C:\Users\UserName\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs’)
$jobDef.Run()

As you can see, the script loads the needed PSScheduledJob module, invokes the static LoadFromStore procedure from the Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition class, passes it the name and path of the job, stores it in a variable named $jobDef, and runs the job in that variable.

Because Task Scheduler doesn’t know about the vagaries of Windows PowerShell, the scheduled job cmdlets automatically add all of the Windows PowerShell details that the Task Scheduler needs. This detail is included in the Scheduled Job in the PSExecutionPath and PSExecutionArgs properties.

Here are the property values from June’s Update-MyHelp scheduled job:

PS C:\> (Get-ScheduledJob Update-MyHelp).PSExecutionArgs

-NoLogo -NonInteractive -WindowStyle Hidden -Command “Import-Module PSScheduledJob; $jobDef = [Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]::LoadFromStore(‘Update-MyHelp’, ‘C:\Users\juneb\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs’); $jobDef.Run()”

PS C:\ > (Get-ScheduledJob Update-MyHelp).PSExecutionPath

powershell.exe

Because of the lack of knowledge of Windows PowerShell internals, the Scheduled Task tools don’t know about the output results of the scheduled jobs. There are no scheduled task cmdlets that enable you to access those run instances the way you can with the Get-Job cmdlet.

Using the path to a scheduled task

That’s great, Dave. When you use the scheduled task cmdlets, note that they use the Task Scheduler path and name to identify a task, not just the task name.

So, when you use the scheduled task cmdlets to get or set a scheduled job, you might need to provide the full Task Scheduler path. Fortunately, it’s easy to get, because it’s the value of the TaskPath property of the task.

For example, this command sequence, which sets a new value for a task setting, fails without the task path:

PS C:\> $s = New-ScheduledTaskSettingsSet -DeleteExpiredTaskAfter (New-TimeSpan -Days 14)

PS C:\> Set-ScheduledTask Update-MyHelp -Settings $s

Set-ScheduledTask : The system cannot find the file specified.

At line:1 char:1

+ Set-ScheduledTask Update-MyHelp -Settings $s

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

    + CategoryInfo          : ObjectNotFound: (PS_ScheduledTask:Root/Microsoft/…S_ScheduledTask) [Set-ScheduledTask]

   , CimException

    + FullyQualifiedErrorId : HRESULT 0x80070002,Set-ScheduledTask

But it succeeds when you add the TaskPath parameter:

PS C:\> $path = (Get-ScheduledTask Update-MyHelp).TaskPath

\Microsoft\Windows\PowerShell\ScheduledJobs\

PS C:\> Set-ScheduledTask Update-MyHelp -Settings $s -TaskPath $path

Can you manage scheduled tasks with Scheduled Jobs cmdlets?

The scheduled job cmdlets expect the tasks to be in the path Task Scheduler located at: Library/Microsoft/Windows/PowerShell/ScheduledJobs

Tasks stored in any other path are not accessible from the scheduled job cmdlets because there is no Path parameter to enable you find tasks in other paths. All scheduled jobs are created in that path, so they are expected to be there. If you need to manipulate a task in any other path, you must use the scheduled task tools and cmdlets to do it.

If you created a scheduled task by any means other than the scheduled job cmdlets, the task is likely stored somewhere other than the PowerShell/ScheduledJobs folder. If that is the case, you must use the scheduled tasks tools and cmdlets because the task simply is not accessible to the scheduled job cmdlets.

When to use scheduled tasks vs. scheduled jobs

So the big question is: which do I use? A scheduled task or a scheduled job? You can use either for most tasks. However, remember that a lot of Windows PowerShell details are exposed in the Scheduled Tasks view of a job to handle the Windows PowerShell specifics that scheduled job cmdlets handle in the background.

If you’re running a Windows executable that is logging to a file or not generating output objects, or if you don’t care about the output, running the tool is probably the easiest way to create a scheduled task. Also, if the task has no need for Windows PowerShell and the overhead that running it entails, you’re better off with a scheduled task.  And if you’re managing failover clusters, definitely use a scheduled task.

But if you’re running Windows PowerShell commands or scripts, or Windows tools that don’t write their output to a file, and the output is important, a scheduled job is the better choice.

The cool part is that, in Windows PowerShell 4.0 and Windows PowerShell 3.0, if you need to create multiple scheduled jobs or tasks on the local computer or on remote computers, you can automate their creation and maintenance with the Scheduled Job or the scheduled task cmdlets.

~June and Dave

Thanks for the great post! 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