Today I'm going to walk you through one of the most underrated functions available in PowerShell: scheduled jobs. Microsoft introduced scheduled jobs in PowerShell v3, but they haven't received a whole bunch of attention from admins over the years. Let's change that!

Scheduled jobs vs. scheduled tasks

Scheduled jobs are batch jobs that run as background tasks created and managed using PowerShell. On the surface, scheduled jobs look, act, and feel much like an old Windows standard: scheduled tasks. The similarity between the two tools often confuses people. For the most part, scheduled jobs and scheduled tasks are the same but apply to different use cases. Microsoft modeled scheduled jobs to be similar to scheduled tasks on purpose so you wouldn't have to learn a new syntax for scheduling.

Scheduled tasks are native to Windows, aiming to interact with Windows and run Windows programs. Similarly, scheduled jobs are native to Windows PowerShell and cannot interact with Windows applications like Notepad, Word, or IE, for example.

So, what's so great about scheduled jobs then? While there are more than a few differences between the two, the biggest difference is with the job results. Scheduled tasks interact with Windows, but they do not capture any results from the tasks performed. Scheduled jobs are essentially PowerShell scripts, and as such, the results of the jobs are objects just like anything else you do with PowerShell. It stores the object data with the results.

If you created a scheduled job to get the running services on a computer, the results data would capture all the information about the services at the time of the job's execution. If you had a scheduled job that pinged a server, it would capture the ping results. It's like you get to go back in time and see what the data looked like at the time of its creation. As I mentioned earlier, since the results are essentially objects, you can manipulate that data and do things like pass the data to other cmdlets if need be. If you created a scheduled task that performs an action, the system does not capture the results of that action anywhere.

Let me briefly discuss management options—here's where it gets confusing. You can only create PowerShell scheduled jobs from the command line. Scheduled tasks have their own set of cmdlets for creation and management. You can use scheduled task cmdlets to view and manage scheduled jobs but not create jobs.

The Windows tool to interact with scheduled tasks is called Task Scheduler. You can create scheduled tasks from Task Scheduler but not scheduled jobs. However, you can view and manage scheduled jobs with the Task Scheduler, but you cannot use the scheduled job cmdlets to manage scheduled tasks in any way. Yes, it is a lot to try and keep track of, and I blame Microsoft for having too many options here.

I also want to point out that I am highlighting the biggest differences between the two technologies, but there are some other subtle differences I don't have the room to explain here. I recommend you read an excellent article from Microsoft that dives deep into the two tools and explains all the differences in depth.

The thing about scheduled jobs that should appeal to you, the administrator, is that you can manage the entire process of creating, managing, deleting, and reviewing results from the command line. You don't need to interact with the GUI at all. Since the PowerShell scheduled jobs are code, you can save them as scripts. If disaster strikes, you can re-run your scripts and have the scheduled jobs back in place in minutes!

Creating a scheduled job

You should be thinking about the following questions when you create your first scheduled job. I'll run through an example and show you how to build up the code based on the answers to the questions.

  • When will the job run?
  • How often will the job run?
  • What code/cmdlets will the code run?
  • What options are necessary to configure the scheduled job?
  • Under what credentials will the job run?
  • What will be the name of the job?

Let's walk through each question and start to build the syntax.

When will the job run? How often will the job run?

A job trigger starts a scheduled job. The cmdlet New-JobTrigger will define how often the job will run (e.g., once, daily, weekly, random, etc.) and when it will start (e.g., Monday at 1:30 p.m.).

$trigger = New-JobTrigger -Once -At 1:30PM

What code/cmdlets will the job run? The code that your scheduled job will run can either be a script block if the code is small enough, or it can call a file.

-file c:\scripts\test-connection.ps1

or

-scriptblock {code}

What options are necessary for the job to run?

Options are the conditions that may be required for the job to run, controlled through the New-ScheduledJobOption cmdlet. These are choices such as RUNELEVATED or STARTIFONBATTERY or REQUIRENETWORK. There are others, but I hope from my brief example you understand these are the more complex options you could use for a job. A scheduled job may have no options at all, but more often than not, they'll have defined options.

$opt = New-ScheduledJobOption -RunElevated -RequireNetwork

Under what credentials will the job run?

We use the Get-Credential cmdlet to consume credentials for the job to "run as."

$cred = Get-Credential -UserName company\someuser

What will be the name of the job? The -name parameter defines the job name

-name Test-DCsAreOnline

One last piece I didn't mention yet is defining how many instances of the job we want to save. Think of this as the job history option. How much history do I want to save? If we don't define this, the default is 32 instances, which may be overkill depending on what your job is doing. Keep in mind, scheduled jobs will save the output. This setting controls how much history you have to look through later on.

-MaxResultCount 10

Now you can take all of that info and build a new job. You use the Register-ScheduledJob cmdlet to pull it all together.

Register-ScheduledJob -Name Test-DCsAreOnline -Trigger $trigger -Credential $cred `
 -FilePath c:\scripts\test-dconline.ps1 -MaxResultCount 5 -ScheduledJobOption $opt

Let's see another example of defining a scheduled job. This time we're defining all of our variables like we would in a script. This scheduled job runs a script that checks the disk space on domain controllers every 12 hours and saves the last 10 results.

#Define the interval to repeat the job
$trigger = New-JobTrigger -Once -At 9:00AM -RepetitionInterval (New-TimeSpan -Hours 12) -RepeatIndefinitely

#Get user credential so that the job has access to the network
$cred = Get-Credential -UserName bigfirm.biz\someuser

#Set job options
$opt = New-ScheduledJobOption -RunElevated -RequireNetwork

Register-ScheduledJob -Name Get-DCDiskSpace -Trigger $trigger -Credential $cred `
 -FilePath c:\scripts\Get-DCDiskSpace.ps1 -MaxResultCount 10  ScheduledJobOption $opt

You can save this code to create a new scheduled job so you can easily run it again in the future or use it as a template to create more scheduled jobs.

Displaying scheduled jobs

You can view your scheduled jobs two ways: PowerShell or in the GUI. First let's take a look at viewing them from PowerShell. One simple command Get-ScheduledJob shows all of your scheduled jobs.

PS C:\scripts> get-scheduledjob | ft -auto

Id Name           JobTriggers Command                                                   Enabled
-- ----           ----------- -------                                                   -------
1  Test-DCsOnline 1           D:\PowerShell_Scripts\AD-Health-Checks\Test-DCsOnline.ps1 False

Remember earlier when I mentioned you could manage your scheduled jobs with the Task Scheduler? You can view and manage scheduled jobs from the command line or from within the Task Scheduler. However, even though you use the Task Scheduler to view your scheduled jobs, they live in a different location in the Task Scheduler window than scheduled tasks.

This first screenshot is of the Task Scheduler. The line items are scheduled tasks, not scheduled jobs.

Scheduled tasks in the Task Scheduler GUI

Scheduled tasks in the Task Scheduler GUI

When using the Task Scheduler to manage your scheduled jobs, you need to look in a different location for the scheduled jobs.

Scheduled jobs in the Task Scheduler GUI

Scheduled jobs in the Task Scheduler GUI

If you go back and look at where I showed you how to view scheduled jobs in PowerShell, you'll notice that the command line ignored the scheduled tasks and only returned scheduled jobs. If you manage your scheduled jobs from the command line, one simple cmdlet Get-ScheduledJob gives you your results.

If you decide to manage your jobs in the Task Scheduler GUI, you need to remember it lists scheduled jobs in a different location than the default scheduled tasks, and, yes, I know this is confusing and a bit silly. That's also why I mentioned at the beginning of this article that it is a bad idea to manage your scheduled jobs in the GUI; it's just confusing to keep track of all the caveats when doing so.

I've given you a quite a bit of information to digest, but I'm far from done. Keep an eye out next week for a follow-up article on managing your scheduled jobs and viewing the results of completed jobs.

Please leave me some feedback in the comments section so I can continue to write useful articles. If there is something you'd like to see me write about or if you have a specific question about this or any or my other articles, please feel free to leave me a note as well.

In my next post I will explain how to manage scheduled jobs with PowerShell.

avataravataravataravataravataravataravatar
13 Comments
  1. Don 5 years ago

    Before  you start explaining all kind of great possibilities in your follow up articles (which I in general highly valuate) can you please explain the basics of scheduling without using hashes or variables – and files storing them – for storing all required and optional parameters? I can’t find out the correct syntax for scheduling for instance updating the powershell help doing so this forever, every month, on the first day at 00.30AM but only if idle for 5 minutes, doing so hidden as elevated as system. I’d like to do this using only 1 line!

    All the powershell help examples local as well as on-line simply do not dig in deep enough (for me)! I do understand the command New-ScheduledJobOption shows options to configure but how?

    I managed to create a simple job like “Register-ScheduledJob -Name “Update Powershell Help” -RunElevated -ScriptBlock { Update-Help }” although deleting and creating the same job again returns the error “The scheduled job definition Update Powershell Help already exists in the job definition store.” Changing and saving the job using the GUI seams to curropt the job store and throws up errors also when running the job afterwards.

    Also next command was throwing errors I couldn’t resolve: “Register-ScheduledJob -Name “Update Powershell Help” -StartIfNotIdle (“False”) -Trigger (“Startup”) -Frequency (“Monthly”;”00:02″) -ScriptBlock { Update-Help }”.

    I tried for instance “Register-ScheduledJob -Name “Update Powershell Help” -New-JobTrigger -Monthly -At 0:30AM -RunElevated -ScriptBlock { Update-Help }”. This resulted in the error “A parameter cannot be found that matches parameter name ‘New-JobTrigger’.”

     

    • Author

      Hi Don,

      Let me see if I can help you out. You said:

      I tried for instance “Register-ScheduledJob -Name “Update Powershell Help” -New-JobTrigger -Monthly -At 0:30AM -RunElevated -ScriptBlock { Update-Help }”. This resulted in the error “A parameter cannot be found that matches parameter name ‘New-JobTrigger’.

      I think your error here is that you are embedding the New-JobTrigger cmd inside the Register-scheduled job cmdlet which is not correct because New-Jobtrigger is not a parameter of the Register-ScheduledJob cmdlet. Also -runelevated is not a parameter of Register-ScheduledJob either.

      To set up the trigger and the scheduled job options correctly you do one of the two scenarios (based on your code).
      1 – You use the -trigger and -scheduledjoboptions switches like so:

      Register-ScheduledJob -Name “Update Powershell Help” -Trigger @{-Monthly -At 0:30AM} -ScheduledJobOption RunElevated -ScriptBlock { Update-Help }”.

      2 – You instantiate the trigger and scheduledjoboption switches as separate cmds and save to a variable, and then call the variable:

      $trigger = New-JobTrigger -Monthly -at 0:30am

      $options = New-ScheduledJobOption – runelevated

      Register-ScheduledJob -Name “Update Powershell Help” -Trigger $trigger  -ScheduledJoboption $options  -ScriptBlock { Update-Help }

      Hope that helps! Also for reference, the help file for Register-ScheduledJobOption includes this example, which is an example of how you should write the syntax.

      Register-ScheduledJob -FilePath “\\Srv01\Scripts\Update-Version.ps1″ -Trigger @{Frequency=Weekly; At=”9:00PM”; DaysOfWeek=”Monday”;
      Interval=2} -ScheduledJobOption @{WakeToRun; StartIfNotIdle; MultipleInstancesPolicy=”Queue”}

      avataravataravatar
  2. Miguel G. 5 years ago

    Does Register-ScheduledJob require an elevated powershell session to succeed? I can’t seem to get it working without an elevated session, the error message is below:

    Register-ScheduledJob : An access denied error occurred when registering scheduled job definition Hello World.  Try running Windows PowerShell with
    elevated user rights; that is, Run As Administrator.
    At line:1 char:1
    + Register-ScheduledJob -ScriptBlock { Write-Output "Hello World" }
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : PermissionDenied: (Microsoft.Power...edJobDefinition:ScheduledJobDefinition) [Register-ScheduledJob], RuntimeException
        + FullyQualifiedErrorId : UnauthorizedAccessToRegisterScheduledJobDefinition,Microsoft.PowerShell.ScheduledJob.RegisterScheduledJobCommand

    If it requires an elevated session, perhaps you could add that to your article? For what it’s worth, I can register a scheduled task without an elevated session so I thought I’d save myself the trouble of registering a scheduled task and leverage jobs instead…. until I can do so without admin rights, this is not as useful in my case.

    Thanks

    • Author

      Hey Miguel,

      You do need to be working in an elevated session, because you are making changes to the machine and without an elevated session, UAC kicks in and stops the process.

      I did a little research to confirm this fact and I stumbled across an article from Richard Siddaway which states:

      …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.

      I will mention that detail in my follow-up article which should be released early next week.

      • zack 5 years ago

        FYI, -RepeatIndefinitely was introduced in powershell 4.0.

        If 3.0 is installed MS has an example of -RepetitionDuration ([TimeSpan]::MaxValue) to do the same thing on their docs page.

  3. Joni Fejes 5 years ago

    Mike,

    Great article!  Extremely helpful.  I need to pass a parameter to my PS script; how would one accomplish this when creating a Scheduled Job?  ex: test.ps1 someparm

    I already have this working in Task Scheduler, but, am investigating using PS Scheduled jobs. Long story…..

    Thanks in advance,

    Joni Fejes

  4. Joni:

    I’m not sure where you want to get your parameters from for your scheduled tasks.. but you should be able to add a -argumentlist <someparam> or -argumentlist “<someparam1> <someparam2>” to your Register-ScheduledJob command line.

    David F.

  5. Tom Molskow 5 years ago

    Great Article!  My job prompts for the user password. is here anyway o ass in password?  Also, I get this prompt as well:

    Supply values for the following parameters:

    Hello:

     

    • Author

      Hi Tom,

      Thank you for the kinds words. You asked about passing in credentials and I am bit confused and need a little more info. Creds come into place in two places here…

      1. Creds for who the job runs as
      2. Creds for what is invoked within the scheduled job.

      Creds for who the job runs as is already covered in the article:

      #Define the interval to repeat the job
      $trigger = New-JobTrigger -Once -At 9:00AM -RepetitionInterval (New-TimeSpan -Hours 12) -RepeatIndefinitely

      #Get user credential so that the job has access to the network
      $cred = Get-Credential -UserName bigfirm.biz\someuser

      #Set job options
      $opt = New-ScheduledJobOption -RunElevated -RequireNetwork

      Register-ScheduledJob -Name Get-DCDiskSpace -Trigger $trigger -Credential $cred `
      -FilePath c:\scripts\Get-DCDiskSpace.ps1 -MaxResultCount 10 ScheduledJobOption $opt

      Can you give me some details on what you’re doing, so I can give you a little bit more targeted help?

  6. Ankit 4 years ago

    Hi,

    Can i schedule powershell script which queries MSOL service using powershell jobs.

    i tried same with task scheduler however it doesnt work does not matter how many things i have:

    passing credential via a secured file.

    running with highest privileges and run even if user logged on or off setting.

    still same. it shows in history that run is completed however no result.

    the same script runs fine if i run it using powershell ISE manually.

    please help…

     

    • Leos Marek (Rank 4) 4 years ago

      Also, what is the exit code in Task Scheduler, is it 0 as Success or different one?

  7. Ankit, have you run it with start-transcript to catch any errors?  I would add a lot of write-verbose -verbose statements to check every step.

    David F. 

  8. Armenio 3 months ago

    Great article man.
    It was very useful to me. Im trying to build an script with the help of chatgpt. Im trying to do a script that prompts username, ad group and a date. With this the script adds the informed user to the informed group and should remove the user from the group when the selected date is reached. Im still working with this last part. Finding some difficult to remove the user when the job start. At the results.xml i can see something like the execution enviroment, or ad status… after reading your tips hopefuly i will reach out what i need.
    Nice job man, God bless you!

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account