Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Cleaning Up PowerShell Jobs

Posted on September 17, 2021September 17, 2021
https://www.pexels.com/photo/person-wearing-white-pants-and-white-socks-standing-beside-brown-broom-4108715/

I am a heavy user of PowerShell jobs. Not only background jobs but also scheduled jobs. They are a critical element in my daily workflow. Every time a job runs, especially scheduled jobs, a job artifact remains which you can see using Get-Job. For scheduled jobs, I try to keep this to a minimum by specifying a MaxResultCount with Register-ScheduledJob. I rarely need to check the results of the job but I like being able to see the job result. However, all of this still leads to a large number of jobs. Here's a taste of what this looks like on my daily driver.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

On one hand, this really isn't that big a deal. The jobs aren't consuming much in the way of disk space or memory and it is nice to have the information if I need to troubleshoot something. Still, it might be nice to be able to clean this up. I could easily wipe away all the jobs with a one-line command.

 Get-Job | where state -ne running | Remove-Job

But, I'd like to leave at least 1 or 2 of the newest job results behind so I can monitor everything. For this task, I wrote a PowerShell function.

#requires -version 5.1

#remove all but the newest X number of jobs based on the job name.

Function Remove-OldJob {
    [cmdletbinding(SupportsShouldProcess)]
    [OutputType("None", "Job")]
    Param(
        [Parameter(Position = 0, HelpMessage = "Specify the newest number of jobs to save for each job name. The max is 10.")]
        [ValidateRange(1, 10)]
        [int]$Newest = 1,
        [Parameter(HelpMessage = "Display the revised job list")]
        [switch]$Passthru
    )
    Write-Verbose "Starting $($myinvocation.MyCommand)"
    Write-Verbose "Saving the newest $newest job result(s)"
    Write-Verbose "Group all jobs that aren't running by their name"
    $jobs = Get-Job | Where-Object state -NE running | Group-Object -Property Name
    if ($jobs) {
        foreach ($item in $jobs) {
            if ($item.count -gt $Newest) {
                Write-Verbose "Processing $($item.count) total jobs for $($item.name)"
                $item.group | Sort-Object psendtime -Descending | Select-Object -Skip $Newest | Remove-Job
            } #foreach item
            else {
                Write-Verbose "Skipping job $($item.name)"
            }
        }
    } #if jobs
    else {
        Write-Warning "No jobs found."
    }

    if ($Passthru) {
        Get-Job | Sort-Object -Property Name
    }
    Write-Verbose "Ending $($myinvocation.MyCommand)"
}

The function works by grouping job results by name.

I wrote the function to take a parameter indicating how many of the newest jobs I want to keep. For each group, if the count is equal to or above this value, I sort the group of jobs by their end time, skipping the specified number of jobs and remove them.

$jobs = Get-Job | Where-Object state -NE running | Group-Object -Property Name
if ($jobs) {
    foreach ($item in $jobs) {
        if ($item.count -gt $Newest) {
            Write-Verbose "Processing $($item.count) total jobs for $($item.name)"
            $item.group | Sort-Object psendtime -Descending | Select-Object -Skip $Newest | Remove-Job
        } #foreach item
        else {
            Write-Verbose "Skipping job $($item.name)"
        }
    }
} #if jobs

Because I'm changing the state of my system, I added SupportsShouldProcess to the cmdletbinding attribute. Because Remove-Job supports -WhatIf, I don't have to code anything special. When I run my command with -WhatIf, the preference gets passed to Remove-Job.

I can then run the command and clean up the job list.

The -Passthru parameter gets the remaining jobs and displays them sorted by name. Normally, I wouldn't include the sort in the function, but in this case, the sorted results make it easy to verify the results. Which in this case is no more than 2 job results for each named job.

You may not need to clean up old job results, but hopefully, there's something in my code that you can use in your own work. As always, comments and questions welcome.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

1 thought on “Cleaning Up PowerShell Jobs”

  1. John Joseph Donnelly says:
    September 17, 2021 at 11:34 am

    Awesome. Thanks for sharing this. This will really help.

    (Also a fan of Bill Chase and his wild horns.. :))

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d