When migrating content, workflows, or site collections into or out of SharePoint Server
Subscription Edition (SE), keeping track of active migration jobs is essential. Whether you are
using the SharePoint Migration Tool (SPMT), the SharePoint Migration API, or native site
upgrade jobs, migration processes rely heavily on background timer jobs and queue definitions
inside your farm.
If a migration appears stuck or you need to verify if a background migration task is currently running
on your farm, running the right PowerShell scripts saves hours of Central Admin hunting.
Here is your complete guide and script toolkit for auditing and verifying SharePoint SE migration
jobs.
Understanding Migration Jobs in SharePoint SE
In SharePoint Server Subscription Edition, migration jobs exist in two primary layers:
SharePoint Timer Jobs ( SPTimerService ): Farm-level background processes running
scheduled tasks across web applications, content databases, and site collections.
Migration API Queues: Background jobs initiated by migration tooling (such as SPMT or
custom PowerShell scripts) that execute content ingestion and workflow transformations
asynchronously.
- Quick Check: Find All Migration-Related Timer Jobs
To check if any migration-related timer jobs exist and are currently scheduled or executing on your
SharePoint SE farm, use Get-SPTimerJob filtered by name or job type:
if ((Get-PSSnapin -Name "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null)
{
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
Write-Host "`n--- Checking SharePoint Migration-Related Timer Jobs ---`n" -ForegroundColor Cyan
$migrationJobs = Get-SPTimerJob | Where-Object {
$_.Name -match "Migration|Migrate" -or
$_.DisplayName -match "Migration|Migrate" -or
$_.TypeName -match "Migration|Migrate"
}
if ($migrationJobs.Count -gt 0)
{
$migrationJobs |
Sort-Object DisplayName |
Select-Object `
DisplayName,
Name,
TypeName,
IsDisabled,
Schedule,
LastRunTime,
WebApplication |
Format-Table -Wrap -AutoSize
}
else
{
Write-Host "No migration-related timer jobs found." -ForegroundColor Yellow
}
- Deep Dive: Check Running Job History and Active Status
Finding the job definition is only half the battle. You also need to verify if the job is currently
running, paused, or failed.
This script queries running job instances and active job history on the farm:
# Check Migration Timer Jobs
Write-Host "--- Checking Migration Timer Jobs ---" -ForegroundColor Cyan
$runningJobs = Get-SPTimerJob |
Where-Object {
$_.IsDisabled -eq $false -and (
$_.Name -like "*Migration*" -or
$_.DisplayName -like "*Migration*" -or
$_.TypeName -like "*Migration*"
)
} |
Select-Object `
DisplayName,
Name,
TypeName,
Schedule,
LastRunTime
if ($runningJobs)
{
$runningJobs | Format-Table -AutoSize
}
else
{
Write-Host "No migration timer jobs found." -ForegroundColor Green
}
- Master SharePoint SE Migration Diagnostic Script
Use this single master script on your SharePoint SE application or front-end server to run a full
diagnostic scan across your farm’s web applications, site collections, and timer job services.
<#
.SYNOPSIS
Audits SharePoint Server Subscription Edition for active, scheduled, or legacy migration jobs.
.DESCRIPTION
Checks timer jobs, site upgrade jobs, and content database migration flags.
#>
Param(
[string]$WebAppUrl = ""
)
# Load SharePoint PowerShell Snap-in
if ((Get-PSSnapin -Name "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null)
{
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
Write-Host "====================================================" -ForegroundColor Cyan
Write-Host " SharePoint SE Migration Job Audit Diagnostic " -ForegroundColor Cyan
Write-Host "====================================================" -ForegroundColor Cyan
# ------------------------------------------------------------------
# 1. Audit Migration Timer Jobs
# ------------------------------------------------------------------
Write-Host "`n[1/3] Auditing Farm Timer Jobs..." -ForegroundColor Yellow
$timerJobs = Get-SPTimerJob | Where-Object {
$_.Name -match "migration|upgrade|spmt|import" -or
$_.DisplayName -match "migration|upgrade|spmt|import"
}
if ($timerJobs)
{
$timerJobs |
Select-Object `
DisplayName,
Name,
IsDisabled,
LastRunTime,
@{Name="Status";Expression={
if ($_.IsDisabled) { "Disabled" } else { "Active" }
}} |
Format-Table -AutoSize
}
else
{
Write-Host " -> No specific migration timer jobs registered." -ForegroundColor Gray
}
# ------------------------------------------------------------------
# 2. Audit Content Database Upgrade Status
# ------------------------------------------------------------------
Write-Host "`n[2/3] Checking Content Databases for Pending Upgrade/Migration Jobs..." -ForegroundColor Yellow
$dbResults = foreach ($db in Get-SPContentDatabase)
{
[PSCustomObject]@{
"Database Name" = $db.Name
"Web Application" = $db.WebApplication.Name
"Status" = if ($db.NeedsUpgrade) {
"Needs Upgrade / Migration Pending"
}
else {
"Healthy / Up To Date"
}
"Current Sites" = $db.CurrentSiteCount
}
}
$dbResults | Format-Table -AutoSize
# ------------------------------------------------------------------
# 3. Check Site Collection Upgrade State
# ------------------------------------------------------------------
Write-Host "`n[3/3] Checking Site Collection Level Upgrade/Migration Queue..." -ForegroundColor Yellow
$sites = if (![string]::IsNullOrWhiteSpace($WebAppUrl))
{
(Get-SPWebApplication $WebAppUrl).Sites
}
else
{
Get-SPSite -Limit All
}
$pendingSites = @()
foreach ($site in $sites)
{
try
{
if ($site.UpgradeInfo -and $site.UpgradeInfo.UpgradeState -ne "NoUpgrade")
{
$pendingSites += [PSCustomObject]@{
"Site URL" = $site.Url
"Upgrade State" = $site.UpgradeInfo.UpgradeState
"Last Updated" = $site.UpgradeInfo.LastUpgradeStartTime
}
}
}
catch
{
Write-Warning "Failed to inspect site: $($site.Url)"
}
finally
{
$site.Dispose()
}
}
if ($pendingSites.Count -gt 0)
{
$pendingSites | Format-Table -AutoSize
}
else
{
Write-Host " -> No site collections are currently queued for upgrade or active migration." -ForegroundColor Green
}
Write-Host "`nAudit complete!" -ForegroundColor Cyan
Admin Tips: Handling Stuck Migration Jobs
Pro Tip for Farm Admins:
Restart the Timer Service: If a migration timer job is stuck in a Running state at 0%
progress, restart the SharePoint Timer Service ( SPTimerV4 ) across all farm servers:
Get-Service SPTimerV4 | Restart-Service
Clear Configuration Cache: If deleted migration jobs continuously reappear or fail to execute,
clear the SharePoint farm configuration cache on all nodes.
Central Admin Verification: You can also verify job status via GUI by navigating to Central
Administration > Monitoring > Timer Jobs > Review job definitions or Check job status.
