SharePoint: All about one-time timer jobs

One-time timer jobs are created ad-hoc, should run immediately, and then disappear when they are done doing whatever they were supposed to do.  If you have one-time timer jobs hanging around, you have a timer service (owstimer.exe) problem.

You can easily find any one-time timer jobs by doing this:
Go to Central Administration | Monitoring | Review Job Definitions
Click the Schedule Type column to sort by that column.
Click it again to sort descending.
Scroll down past the Weekly timer jobs.  Any one-time jobs should be between Weekly and Monthly.

You can also use this PowerShell to identify one-time timer jobs:
Get-SPTimerJob | ?{$_.schedule.description -eq "One-time"} |select displayname,server,locktype,lastruntime | fl

I don’t pretend to know all the situations where one-time timer jobs are used, but here are some common scenarios, listed with the name of the one-time timer job it creates:
  • Starting the User Profile Synchronization Service: “ProfileSynchronizationSetupJob”
  • Extending a Web Application or creating a new one: “Provisioning Web Application <web app name>”
  • Creating new service applications: “Service Application Instance Provisioning Job”
  • Updating service account passwords: “Password Change Event”
  • Changing the SharePoint Logging levels: “Microsoft SharePoint Foundation Diagnostics Service Configuration”
  • Starting or stopping services on any server other than the Central Admin box: “Provisioning <the name of the service> service on <serverName>” Ex: "Provisioning App Management Service service on ContosoAPP01"
-- In general, most farm administration tasks that includes work that must be completed on other servers in the farm will use a one-time timer job to do it.

So what to do if one-time timer jobs are NOT running?

If one-time timer jobs are not running, it's usually one of three problems:

1.  The timer service "service instance object" is offline / disabled:

Public articles about this issue:

-- Here’s my take on the PowerShell Script to enable the timer instances, which also outputs the status of AllowServiceJobs and AllowContentDatabaseJobs for each box, which is useful for SharePoint 2016:

#Make sure the Timer service instances are online 
#and check the values for AllowServiceJobs and AllowContentDatabaseJobs
Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue
$farm = Get-SPFarm 
$FarmTimers = $farm.TimerService.Instances 
foreach ($FT in $FarmTimers){write-host "Server: " $FT.Server.Name.ToString(); write-host "Status: " $FT.status; write-host "Allow Service Jobs: " $FT.AllowServiceJobs; write-host "Allow Content DB Jobs: " $FT.AllowContentDatabaseJobs;"`n"}
$disabledTimers = $farm.TimerService.Instances | where {$_.Status -ne "Online"} 
if ($disabledTimers -ne $null) 
{foreach ($timer in $disabledTimers) 
{Write-Host -ForegroundColor Red "Timer service instance on server " $timer.Server.Name " is NOT Online. Current status:" $timer.Status 
Write-Host -ForegroundColor Green "Attempting to set the status of the service instance to online..." 
$timer.Status = [Microsoft.SharePoint.Administration.SPObjectStatus]::Online 
write-host -ForegroundColor Red "You MUST now go restart the SharePoint timer service on server " $timer.Server.Name}} 
else{Write-Host -ForegroundColor Green  "All Timer Service Instances in the farm are online. No problems found!"}     

2. A problem with the SharePoint Administration service.

The SharePoint Administration service (aka: SPAdminV4, WSSADMIN.EXE) is also involved in the execution of one-time timer jobs.  Make sure that this service is running on every server in the farm and the log on account must be "Local System".  
-- It doesn’t hurt to restart the Administration service and the Timer service just to make sure nothing is hung up there.

You may also be able to force one-time timer jobs to run on the local server by temporarily stopping the Administration service and running this:
stsadm -o execadmsvcjobs

3. Bloated TimerJobHistory table (like millions of rows).

If the TimerJobHistory table (in the Configuration database) accumulates a large number of records (millions) over time and the "Delete Job History" timer job is not able to keep up with the number of records being added, one-time timer jobs will fail to run.

To check for this issue, run the following two SQL queries against the Configuration database:

-- Show total rows:
select COUNT(*) from TimerJobHistory (nolock)
-- Show oldest records
select top 10 ID, StartTime, EndTime from TimerJobHistory (nolock) 
order by StartTime

Or, if you don't have access to your SQL server to run direct queries, you can run this PowerShell to give you the same information.  Be sure to be logged on as the Farm service account, or another account that has access to the Configuration database:

# Check Timer job history table via SQL query using PowerShell
# This PowerShell script is provided "as-is" with no warranties expressed or implied. Use at your own risk.
Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn1 = New-Object System.Data.SqlClient.SqlConnection
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd1 = New-Object System.Data.SqlClient.SqlCommand
$configDb = Get-SPDatabase | ?{$_.TypeName -match "Configuration Database"}
$connectionString = $configDb.DatabaseConnectionString
$conn.ConnectionString = $connectionString
$cmd.connection = $conn
$conn1.ConnectionString = $connectionString
$cmd1.connection = $conn1
Write-Host "Issuing Query on: " $configDb.Name ""
$cmd.CommandText = "select COUNT(*) from TimerJobHistory (nolock)"
$rows = $cmd.ExecuteReader()
if($rows.HasRows -eq $true)
{"Timer Job History Table contains: " + $rows[0]+ " rows"}
$cmd1.CommandText = "select top 10 ID, StartTime, EndTime from TimerJobHistory (nolock) order by StartTime"
$rows1 = $cmd1.ExecuteReader()
if($rows1.HasRows -eq $true)
{"Top 10 Oldest Records in Timer Job History Table: "
{$rows1[0].ToString() + " ~ " + $rows1[1].ToString() + " ~ " + $rows1[2].ToString()


Then, run the following PowerShell on one of the SharePoint servers to get information about the job that is supposed to keep TimerJobHistory cleaned up:

Get-SPTimerJob | ?{$ -eq "job-delete-job-history"} | fl
  • Getting a record count (SQL query 1) is a good indicator.  If it's several million rows, that’s a pretty sure bet it's causing problems.
  • The second query will show you the oldest records in that table.  By default, they should be no older than 7 days.
  • The PowerShell output of "job-delete-job-history" is to verify that the cleanup job is enabled and what "DaysToKeepHistory" is set to.  Should be 7.
If this is the problem, you have a couple options:
  • Figure out what is wrong with the "job-delete-job-history" timer job and hopefully it will be able to catch up and clean up that table to a reasonable number of rows.
  • Contact Microsoft Support.  We have ways of manually cleaning it up.  I’m not going to detail that method here because it’s unsupported for anyone except support engineers with the proper approvals to complete.

Update! The November 2017 CU (build 15.0.4981.1002) changed the behavior around TimerJobHistory table cleanup. Essentially it's now done as part of every timer job.

However, if you already have a bloated TimerJobHistory table at time of upgrade, it can initially cause more problems than it solves. See Stefans blog post about it.


Comments (1)

  1. Thanks !! This solved my problem – my CA server was showing the timer job as offline, but it was online in the WFE. Just setting it to be “online” -and resetting the TIMERJOB server on the WFE made it work again. Thanks again…

Skip to main content