Summary: Richard Siddaway introduces you to scheduled PowerShell jobs.
Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy. This is the fourth in a series of posts that, hopefully, will shine the spotlight on Windows PowerShell jobs, remind people of their capabilities, and encourage their greater adoption. The full series comprises:
- Introduction to PowerShell Jobs
- WMI and CIM Jobs
- Remote Jobs
- Scheduled Jobs (this post)
- Jobs and Workflows
- Job Processes
- Jobs in the Enterprise
So far, you’ve discovered the core cmdlets for working with Windows PowerShell jobs, investigated using WMI and CIM cmdlets in jobs, and learned how to run jobs on remote machines. Today we go off on a little bit of a tangent and discover how scheduled jobs work.
Windows PowerShell 3.0 introduced two modules that can be confused:
- PSScheduledJob
- ScheduledTasks
The ScheduledTasks module is for working with the Task Scheduler. It is a CDXML (WMI-based) module that is only found in Windows 8.1, Windows 8, Windows Server 2012 R2, and Windows 2012. It is not part of the WMF 4.0 or WMF 3.0 download that is available for legacy versions of Windows.
The PSScheduledJob module is a binary module that is part of the WMF 4.0 and WMF 3.0 downloads, and it is natively installed in Windows 8.1, Windows 8, Windows Server 2012 R2, and Windows 2012.
Having cleared up that bit of confusion, the next question is, “What’s a scheduled job?”
The easiest way to answer that is to quote from the Help file: “Windows PowerShell scheduled jobs are a useful hybrid of Windows PowerShell background jobs and Task Scheduler tasks.”
In addition to the cmdlet Help files, there is also a set of about_ files:
- about_Scheduled_Jobs
- about_Scheduled_Jobs_Advanced
- about_Scheduled_Jobs_Basics
- about_Scheduled_Jobs_Troubleshootingd
I would strongly recommend that you read the information in these files.
Scheduled jobs are like normal jobs in that they run asynchronously in the background, and they can be managed by using the core Windows PowerShell job cmdlets. They also have an aspect of Task Scheduler tasks because they can be saved to disk and run to a schedule or on an ad hoc basis like any other scheduled task.
Now that you know what they are, how do you work with them?
The first thing to do with any new module is to have a look at the cmdlets it contains:
Get-Command -Module PSScheduledJob | sort noun, verb
- Add-JobTrigger
- Disable-JobTrigger
- Enable-JobTrigger
- Get-JobTrigger
- New-JobTrigger
- Remove-JobTrigger
- Set-JobTrigger
- Disable-ScheduledJob
- Enable-ScheduledJob
- Get-ScheduledJob
- Register-ScheduledJob
- Set-ScheduledJob
- Unregister-ScheduledJob
- Get-ScheduledJobOption
- New-ScheduledJobOption
- Set-ScheduledJobOption
There are three groups of cmdlets for working with JobTriggers, ScheduledJobs, and ScheduledJobOptions. Let’s work through these by creating a new scheduled job.
Start by creating a new trigger for the scheduled job. You can add triggers to the job after it’s created:
$trigger = New-JobTrigger -Daily -At "19:15"
This trigger sets the scheduled job to start at 19:15 (7:15pm) every day. The usual possibilities with scheduled tasks are available so you can have jobs that run on particular days, at logon or startup, every N days, on specific days of the week, or every N weeks.
There are a number of options you can use with your scheduled job. In this case, the job will run with elevated privileges, and it will continue even if the machine goes on battery power:
$option = New-ScheduledJobOption -RunElevated –ContinueIfGoingOnBattery
The final part is to register the job:
Register-ScheduledJob -Name HSG1 -ScriptBlock {Get-Process} -Trigger $trigger -ScheduledJobOption $option
You need to provide a name, a script block that you want the job to run, and the trigger and options. When your job registers, you will see the type of output shown in the previous screenshot.
There is a clue to one important point that you need to remember in the title bar of the Windows PowerShell console shown in the previous screenshot. You have to be running Windows PowerShell with elevated privileges when you create scheduled jobs.
Your scheduled jobs can be found in the Task Scheduler under:
\Microsoft\Windows\PowerShell\ScheduledJobs.
If you want to see the results of your scheduled job immediately as a test, you have two options. First, you can add the
–RunNow parameter when you use Register-ScheduledJob. This will run your scheduled job once. This parameter is only available in Windows PowerShell 4.0.
Alternatively, if you’ve set your scheduled job to run sometime in the future, you can test the job by using Start-Job.
Start-Job is used with the –Definition name parameter. This causes the scheduled job to be run as a standard job. But note the job type: PSScheduledJob. The results will be subject to the standard rules for Windows PowerShell jobs rather than being stored on disk as happens with scheduled jobs.
The results of scheduled jobs are persisted to disk. You can view the scheduled jobs that have run, but there are a couple of caveats:
- You can only see the jobs that you create and run in your context due to the way scheduled jobs and output is stored in your profile.
- You have to explicitly import the PSScheduledJob module into your session to be able to work with scheduled job results.
You can use the job name to discover the completed jobs, as shown here:
You can also use the job type:
Get-Job | where PSJobTypeName -eq PSScheduledJob
You can fetch the data in the job by using Receive-Job:
Receive-Job -Id 6
Notice that I didn’t use the –Keep parameter. This means that the HasMoreData property is set to False:
£> Get-Job -Id 6 | Format-List Id, Name, PSJobTypeName, State, HasMoreData, Location, Command
Id : 6
Name : HSG1
PSJobTypeName : PSScheduledJob
State : Completed
HasMoreData : False
Location : localhost
Command : Get-Process
I had to define the properties in Format-List because Get-Job displays all of the data by default in list view. However, if you open another Windows PowerShell session, import the PSScheduledJob module again, and try Get-Job, you will see that your scheduled job appears to have miraculously regained its data. That’s because the data isn’t actually removed from the job, and when you get the jobs from the store in your new session (for example: C:\Users\Richard\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs\HSG1\Output), the information is refreshed.
It’s still advisable to use the –Keep parameter so that you can look at the data again in the same session, if required.
You can see how long your jobs took:
£> Get-Job -Name HSG1 | Format-Table Name, PSBeginTime, PSEndTime -AutoSize
Name PSBeginTime PSEndTime
---- ----------- ---------
HSG1 25/02/2014 21:00:23 25/02/2014 21:00:25
HSG1 25/02/2014 21:09:56 25/02/2014 21:09:58
HSG1 25/02/2014 21:10:03 25/02/2014 21:10:05
Pick one of the jobs, and drill down into the definition:
£> Get-Job -Id 6 | select -ExpandProperty Definition | Format-List *
InvocationInfo : Microsoft.PowerShell.ScheduledJob.ScheduledJobInvocationInfo
Definition : System.Management.Automation.JobDefinition
Options : Microsoft.PowerShell.ScheduledJob.ScheduledJobOptions
Credential :
JobTriggers : {1}
Id : 5
GlobalId : 409993f2-1990-43f8-acf1-3012a89cbde4
Name : HSG1
Command : Get-Process
ExecutionHistoryLength : 32
Enabled : True
PSExecutionPath : powershell.exe
PSExecutionArgs : -NoLogo -NonInteractive -WindowStyle Hidden -Command "Import-Module PSScheduledJob; $jobDef =
[Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]::LoadFromStore('HSG1',
'C:\Users\Richard\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs'); $jobDef.Run()"
The last part is interesting, and it shows how the scheduled job is actually run.
By default, Windows PowerShell will keep 32 instances of a scheduled job’s results. When that number is exceeded, it will start deleting the oldest jobs. You can see the number of results that will be kept:
£> Get-ScheduledJob -Name HSG1 | select -ExpandProperty ExecutionHistoryLength
32
The number can be altered as required:
£> Get-ScheduledJob -Name HSG1 | Set-ScheduledJob -MaxResultCount 50
£> Get-ScheduledJob -Name HSG1 | select -ExpandProperty ExecutionHistoryLength
50
To remove results:
Get-ScheduledJob -Name HSG1 | Set-ScheduledJob –ClearExecutionHistory
Alternatively, you can use Remove-Job as with other job types.
To delete the scheduled job, you need to unregister it:
Get-ScheduledJob -Name ProcessJob | Unregister-ScheduledJob
If you want a complete clean sweep of the scheduled jobs, use this:
Get-ScheduledJob | Unregister-ScheduledJob
Scheduled jobs fall between scheduled tasks and Windows PowerShell jobs. Which should you use? It depends on what you are trying to achieve. The great advantage of scheduled jobs is that they automatically call Windows PowerShell for you, and you have the job cmdlets to manage the results. It is especially useful that the data is persisted to disk.
That’s it for today. Tomorrow you’ll learn about using jobs with your Windows PowerShell workflows. Bye for now.
~Richard
Thanks, Richard. I’m looking forward to the remainder of your series.
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