Posted in

Monitoring SharePoint SE Migration Jobs:Essential PowerShell Scripts for Farm Admins

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.

  1. 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
}
  1. 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
}
  1. 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.

Moving beyond the basics to master the art of automation. We share battle-tested snippets, time-saving hacks, and deep dives for the modern maker. Built by enthusiasts, for enthusiasts. Let’s automate the tedious and build the exceptional Microsoft Power Automate

Leave a Reply

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