Optimizing PowerShell Scheduled Jobs
In the first part of this series I demonstrated how to create a simple PowerShell scheduled job, where you can take your existing PowerShell scripts and easily run them as scheduled tasks. Today, I want to give you a little more information on what’s happening behind the scenes.
Here are the scheduled jobs that I’ve set up.
In my previous article, I set up the first job. Let’s look at it from PowerShell’s perspective in more detail.
I’ve highlighted the execution details. The scheduled task is launching PowerShell.exe and running a complicated command. You can see the same thing in the Task Scheduler.
Say Goodbye to Traditional PC Lifecycle Management
Traditional IT tools, including Microsoft SCCM, Ghost Solution Suite, and KACE, often require considerable custom configurations by T3 technicians (an expensive and often elusive IT resource) to enable management of a hybrid onsite + remote workforce. In many cases, even with the best resources, organizations are finding that these on-premise tools simply cannot support remote endpoints consistently and reliably due to infrastructure limitations.
Here’s how the magic happens. When you create a PowerShell scheduled job, it has to be persisted to disk so that the Task Scheduler knows what to execute. The files for each job are stored under $env:LocalAppData\Microsoft\Windows\PowerShell\ScheduledJobs.
There is a directory for each scheduled job. Within each directory is an XML file with the job definition and the results.
Don’t bother trying to parse the XML file. You can grab everything you need from this file with the scheduled job cmdlets. Because the output is also persisted to disk, you can always get the job results.
Again, you don’t need to be concerned about parsing these results. Instead use the job cmdlets.
I modified my original script to get the report file, but there’s one caveat. If you want to see these type of job results in PowerShell 3.0, you need to first import the PSScheduledJob module. In PowerShell 4.0, this module is imported automatically. You should get results every time the job runs regardless of whether you scheduled the task to run automatically or manually ran the task from PowerShell or the Task Scheduler.
The job results will persist between PowerShell sessions and overtime this can clutter your job listings. When you register a scheduled job, it will retain the 32 most recent results by default. That’s what my current job is doing. Look at second figure again and notice the ExecutionHistoryLength parameter. I’m going to change the current job to only keep the five most recent results.
get-scheduledjob "dc service report" | Set-ScheduledJob -MaxResultCount 5
If you know in advance how many results to retain, Register-ScheduledJob also has a MaxResultCount property. Otherwise, you can manually delete job results like any other job.
get-job -Name "DC Service Report" | Remove-Job
If you unregister a job, this will not only remove it from the Task Scheduler, but it will also delete all the associated files, which means you will lose any job results. If you need to, you can easily disable a job so that it won’t remove anything.
When you are ready to resume, use Enable-ScheduledJob.
The scheduled job cmdlets aren’t perfect. You may find that you need to tweak the scheduled task itself. To start, let’s say I want to adjust my current job trigger.
Perhaps I only need this to run Monday through Friday.
get-jobtrigger -Name "DC Service Report" | Set-JobTrigger -Weekly -DaysOfWeek "Monday","Tuesday","Wednesday","Thursday","Friday"
As you can see, this changed the scheduled task.
Be careful though because when you change trigger types, I went from daily to weekly, it changes the job. Now when I run the job I get access denied because I lost the credential.
get-scheduledjob "DC Service Report" | Set-ScheduledJob -Credential globomantics\jeff
Ideally, you want to get everything right the first time when you create the scheduled job. But let’s say I want to run this when I log on to my computer and then once again every hour. If you look at help for New-JobTrigger, there is no parameter set that will let me do that. I will have to manually change it in the Task Scheduler.
PowerShell can’t see the repetition information when it comes to the scheduled job.
I think for the majority of you this shouldn’t be a problem, but I wanted you to be aware. And there is one more gotcha with scheduled jobs. I have another scheduled job set up.
But the job never works.
Looking at the job in Task Scheduler tells me that the “last run of the task was terminated by the user (0x41306).” Turns out there is an odd bug when creating a weekly job using alternate credentials, which has been reported to Microsoft.
When I created the job, I was logged on as Globomantics\Jeff, but I configured the job to use Globomantics\Administrator. If I change the job credential to my Jeff account, it appears to work. The bottom line is that you will need to carefully test all of this in a non-production environment.
I see PowerShell scheduled jobs as the reward for learning PowerShell in the first place. You should be able to automate the routine, the mundane and the boring right out of your day. If you are using scheduled jobs, I’d love to hear what problems they are solving.