Tutorial: SharePoint Migration with SPMT¶
Status: Authored 2026-04-30 Audience: SharePoint administrators executing their first migration from SharePoint Server on-premises to SharePoint Online using the SharePoint Migration Tool (SPMT). Scope: End-to-end walkthrough: download, configure, scan, migrate, validate, and remediate errors.
Prerequisites¶
Before starting this tutorial, ensure:
- SharePoint Online tenant is provisioned and accessible
- Entra ID (Azure AD) Connect is configured and syncing users
- You have SharePoint Administrator or Global Administrator role in M365
- You have Farm Administrator access to the on-premises SharePoint farm
- Network connectivity between the SPMT workstation and both source (on-prem) and target (SPO)
- Source SharePoint Server version: 2010, 2013, 2016, or 2019
- Target site collections exist in SPO (or will be created during migration)
Step 1: Download and install SPMT¶
1.1 Download SPMT¶
# Download SPMT from Microsoft
# https://aka.ms/spmt-ga-page
# Or install via winget:
winget install Microsoft.SharePointMigrationTool
SPMT is a free desktop application that runs on Windows 10/11. It requires:
- Windows 10 (1607+) or Windows 11
- .NET Framework 4.6.2+
- 4 GB RAM minimum (8 GB recommended)
- 50 GB free disk space for temporary migration files
1.2 Install SPMT PowerShell module¶
# Install the SPMT PowerShell module for scripted migrations
Install-Module -Name Microsoft.SharePoint.MigrationTool.PowerShell -Scope CurrentUser
# Verify installation
Get-Module -Name Microsoft.SharePoint.MigrationTool.PowerShell -ListAvailable
1.3 First launch¶
- Launch SPMT from the Start menu
- Sign in with your M365 administrator account
- Accept the license terms
- SPMT connects to your SPO tenant and validates permissions
Step 2: Configure source and target¶
2.1 GUI-based configuration¶
- Click Start your first migration
- Select SharePoint Server as the source
- Enter the source SharePoint site URL:
https://sp2016.contoso.com/sites/finance - Enter credentials for the on-premises farm (Windows authentication or forms)
- Select the target SPO site:
https://contoso.sharepoint.com/sites/finance - Choose migration scope:
- Migrate all -- migrates everything in the site (recommended for first migration)
- Select specific lists/libraries -- granular selection
2.2 PowerShell-based configuration¶
Import-Module Microsoft.SharePoint.MigrationTool.PowerShell
# Initialize SPMT session
$spoCredential = Get-Credential -Message "Enter M365 admin credentials"
Register-SPMTMigration `
-SPOUrl "https://contoso.sharepoint.com" `
-SPOCredential $spoCredential `
-Force
# Configure migration settings
$globalSettings = @{
MigrateFileVersionHistory = $true
KeepAllVersions = $false
NumberOfVersionToMigrate = 10
EnableIncremental = $true
PreserveUserPermissionsForDocumentLibrary = $true
PreserveUserPermissionsForLists = $true
MigrateHiddenItems = $true
AzureActiveDirectoryLookup = $true
UserMappingCSVFile = "C:\Migration\user-mapping.csv"
FilterOutPathSpecialCharacters = $true
MigrateOneNoteNotebook = $true
SkipListWithAudienceEnabled = $false
CustomAzureAccessKey = "" # Use default Azure storage
CustomAzureStorageAccount = "" # Use default Azure storage
}
Step 3: Run pre-migration scan¶
3.1 SPMT pre-scan¶
Before migrating content, SPMT can scan the source to identify issues:
# Add a migration task (scan only)
Add-SPMTTask `
-SharePointSourceSiteUrl "https://sp2016.contoso.com/sites/finance" `
-TargetSiteUrl "https://contoso.sharepoint.com/sites/finance" `
-MigrateAll
# Review scan results before starting migration
# SPMT displays warnings and blockers in the task list
3.2 Common scan findings¶
| Finding | Severity | Resolution |
|---|---|---|
| File name contains invalid characters | Warning | Rename files to remove # % & and other restricted characters |
| File path exceeds 400 characters | Blocker | Shorten folder names or restructure hierarchy |
| File size exceeds 250 GB | Blocker | Split file or store in Azure Blob Storage |
| Checked-out file | Warning | Force check-in before migration |
| InfoPath form library | Warning | Content migrates; forms will not render in SPO |
| Workflow associations | Warning | Workflows do not migrate; plan Power Automate replacement |
| Sandbox solution | Warning | Solution does not deploy to SPO; plan SPFx replacement |
| Custom web parts | Warning | Server-side web parts will not render in SPO |
| List exceeds 100,000 items | Warning | Consider alternatives for very large lists |
| Managed metadata columns | Info | Ensure term store is migrated before content |
3.3 Run SMAT for deeper assessment¶
# SMAT provides more detailed assessment than SPMT pre-scan
# Download from https://www.microsoft.com/download/details.aspx?id=53598
.\SMAT.exe -SiteURL https://sp2016.contoso.com `
-OutputFolder C:\SMAT-Results `
-Verbose
# Review reports in C:\SMAT-Results\
# Key reports:
# - ScanSummary.csv -- overview of all findings
# - LargeListFiles.csv -- lists exceeding thresholds
# - CheckedOutFiles.csv -- files checked out by users
# - CustomizedFiles.csv -- unghosted (customized) pages
# - WorkflowAssociations2010.csv -- SP 2010 workflow inventory
# - WorkflowAssociations2013.csv -- SP 2013 workflow inventory
# - InfoPathForms.csv -- InfoPath form inventory
# - SandboxSolutions.csv -- sandbox solution inventory
Step 4: Execute migration¶
4.1 GUI migration¶
- After scan results are reviewed, click Migrate in the SPMT interface
- SPMT uploads content to a temporary Azure storage location
- Content is then imported into SPO from Azure storage
- Progress is displayed in real-time with item counts, errors, and warnings
4.2 PowerShell migration¶
# Single site migration
Add-SPMTTask `
-SharePointSourceSiteUrl "https://sp2016.contoso.com/sites/finance" `
-TargetSiteUrl "https://contoso.sharepoint.com/sites/finance" `
-MigrateAll
# Start migration
Start-SPMTMigration
# Monitor progress
# SPMT writes logs to %APPDATA%\Microsoft\MigrationTool\Logs\
4.3 Batch migration with multiple tasks¶
# Define multiple migration tasks
$tasks = @(
@{
Source = "https://sp2016.contoso.com/sites/finance"
Target = "https://contoso.sharepoint.com/sites/finance"
},
@{
Source = "https://sp2016.contoso.com/sites/hr"
Target = "https://contoso.sharepoint.com/sites/hr"
},
@{
Source = "https://sp2016.contoso.com/sites/legal"
Target = "https://contoso.sharepoint.com/sites/legal"
},
@{
Source = "https://sp2016.contoso.com/sites/marketing"
Target = "https://contoso.sharepoint.com/sites/marketing"
}
)
foreach ($task in $tasks) {
Add-SPMTTask `
-SharePointSourceSiteUrl $task.Source `
-TargetSiteUrl $task.Target `
-MigrateAll
Write-Host "Added task: $($task.Source) -> $($task.Target)"
}
# Start all tasks
Start-SPMTMigration
Write-Host "Migration started. Monitor progress in SPMT GUI or log files."
4.4 Selective migration (specific libraries)¶
# Migrate specific document libraries only
Add-SPMTTask `
-SharePointSourceSiteUrl "https://sp2016.contoso.com/sites/finance" `
-SharePointSourceDocumentLibraryName "Shared Documents" `
-TargetSiteUrl "https://contoso.sharepoint.com/sites/finance" `
-TargetDocumentLibraryName "Shared Documents"
Add-SPMTTask `
-SharePointSourceSiteUrl "https://sp2016.contoso.com/sites/finance" `
-SharePointSourceDocumentLibraryName "Policies" `
-TargetSiteUrl "https://contoso.sharepoint.com/sites/finance" `
-TargetDocumentLibraryName "Policies"
Start-SPMTMigration
Step 5: Validate migration results¶
5.1 Review SPMT reports¶
After migration completes, SPMT generates detailed reports:
# SPMT log location
$logPath = "$env:APPDATA\Microsoft\MigrationTool\Logs"
# Key log files:
# - StatusReport.csv -- Overall migration status per task
# - ItemReport.csv -- Per-item migration status
# - ScanReport.csv -- Pre-scan findings
# - FailureReport.csv -- Failed items with error details
# - WarningReport.csv -- Items migrated with warnings
# Review failures
$failures = Import-Csv "$logPath\<session>\FailureReport.csv"
$failures | Group-Object -Property ErrorMessage | Sort-Object Count -Descending |
Select-Object Count, Name | Format-Table -AutoSize
5.2 Content validation¶
# Connect to target SPO site
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/finance" -Interactive
# Compare document counts
$targetLibraries = Get-PnPList | Where-Object {
$_.BaseType -eq "DocumentLibrary" -and -not $_.Hidden
}
$targetLibraries | ForEach-Object {
[PSCustomObject]@{
Library = $_.Title
ItemCount = $_.ItemCount
SizeMB = [math]::Round($_.ParentWeb.Usage.Storage / 1MB, 2)
}
} | Format-Table -AutoSize
# Spot-check specific documents
$testDoc = Get-PnPFile -Url "/sites/finance/Shared Documents/Budget2026.xlsx" -AsListItem
Write-Host "Title: $($testDoc['FileLeafRef'])"
Write-Host "Created: $($testDoc['Created'])"
Write-Host "Modified: $($testDoc['Modified'])"
Write-Host "Created By: $($testDoc['Author'].Email)"
Write-Host "Modified By: $($testDoc['Editor'].Email)"
5.3 Permission validation¶
# Verify site permissions
Get-PnPSiteGroup | ForEach-Object {
[PSCustomObject]@{
Group = $_.Title
Members = $_.Users.Count
Roles = ($_.Roles | Select-Object -ExpandProperty Name) -join ", "
}
} | Format-Table -AutoSize
# Verify site collection administrators
Get-PnPSiteCollectionAdmin | Select-Object Title, Email | Format-Table -AutoSize
Step 6: Remediate errors¶
6.1 Common error remediation¶
| Error | Cause | Fix |
|---|---|---|
FileNameContainsInvalidCharacters | Characters like # % & in filename | Rename source file, re-run incremental |
FilePathTooLong | Full URL path > 400 chars | Shorten folder names in source |
FileSizeExceedsLimit | File > 250 GB | Cannot migrate; use Azure Blob Storage |
UserNotFound | On-prem user not in Entra ID | Add user to Entra or update user mapping CSV |
TargetSiteNotFound | Target SPO site does not exist | Create target site before re-running |
AccessDenied_Source | Insufficient permissions on source | Verify farm admin access |
AccessDenied_Target | Insufficient permissions on target | Verify SPO admin role |
ContentTypeMismatch | Content type does not exist in target | Create content type in target before re-running |
ManagedMetadataTermNotFound | Term not in SPO term store | Migrate term store before content |
Throttled | SPO API throttling | Wait and retry; reduce parallel tasks |
6.2 Incremental re-run for failed items¶
# Re-run migration to capture failed items and new changes
# SPMT automatically runs incrementally -- only processes changed/failed items
Register-SPMTMigration `
-SPOUrl "https://contoso.sharepoint.com" `
-SPOCredential $spoCredential `
-Force
Add-SPMTTask `
-SharePointSourceSiteUrl "https://sp2016.contoso.com/sites/finance" `
-TargetSiteUrl "https://contoso.sharepoint.com/sites/finance" `
-MigrateAll
Start-SPMTMigration
# Only failed/changed items will be processed
Step 7: Post-migration tasks¶
7.1 Convert classic pages to modern¶
# Use PnP PowerShell to convert classic pages to modern
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/finance" -Interactive
# Convert a single page
ConvertTo-PnPPage -Identity "Home.aspx" -Overwrite
# Convert all pages in a site
$pages = Get-PnPListItem -List "Site Pages" |
Where-Object { $_["ContentType"].Name -ne "Site Page" }
foreach ($page in $pages) {
try {
ConvertTo-PnPPage -Identity $page["FileLeafRef"] -Overwrite
Write-Host "Converted: $($page['FileLeafRef'])" -ForegroundColor Green
} catch {
Write-Warning "Failed to convert: $($page['FileLeafRef']) - $($_.Exception.Message)"
}
}
7.2 Configure search¶
SharePoint Online search indexes content automatically. After migration:
- Wait 24-48 hours for full indexing
- Verify search returns migrated content
- Configure managed properties for custom metadata
- Set up result sources if needed
- Configure Microsoft Search bookmarks for common queries
7.3 Redirect users¶
# Add URL redirect from old site to new site
# Option 1: IIS URL Rewrite on on-premises web servers
# Option 2: DNS redirect
# Option 3: SharePoint redirect page
# Create a redirect page on the old site
$oldWeb = Get-SPWeb "https://sp2016.contoso.com/sites/finance"
$oldWeb.AllProperties["__RedirectUrl__"] = "https://contoso.sharepoint.com/sites/finance"
$oldWeb.Update()
7.4 Set source to read-only¶
# Lock the source site collection after migration is validated
Set-SPSite -Identity "https://sp2016.contoso.com/sites/finance" -LockState ReadOnly
Step 8: Migration timeline template¶
| Day | Activity | Duration |
|---|---|---|
| Day 1 | Install SPMT, configure settings, create user mapping | 4 hours |
| Day 2 | Run SMAT assessment, review findings | 4 hours |
| Day 3-4 | Remediate blockers (rename files, fix paths, migrate term store) | 8-16 hours |
| Day 5 | Run SPMT pre-scan, review warnings | 4 hours |
| Day 6-7 | Execute initial migration (off-hours) | 8-48 hours |
| Day 8 | Validate migration results, check reports | 4 hours |
| Day 9 | Remediate failed items, run incremental | 4 hours |
| Day 10 | Convert classic pages to modern | 4 hours |
| Day 11 | Final incremental sync | 4 hours |
| Day 12 | Cutover: redirect users, set source to read-only | 2 hours |
| Day 13-14 | Monitor, validate search, support users | 8 hours |
References¶
- SPMT documentation
- SPMT prerequisites
- SPMT supported features
- SPMT PowerShell reference
- SMAT documentation
- PnP page transformation
Maintainers: csa-inabox core team Last updated: 2026-04-30