During a recent client project, we successfully migrated approximately 4,000 Team sites, totaling around 50 TB of data. I wanted to share the methodology we used, including the scripts, as it might be helpful for anyone in the community looking for a similar approach for their clients.
1. Migration Approach
1.1. Team Structure Creation
- Copy Team with Data or Without Data:
- For small team sites, copy the team structure along with data.
- For large team sites, copy the team structure without data initially, then run Copy Site to transfer the contents and entire structure from source to target.
- Note: We recommend the latter approach for all team sites, regardless of size as Sharegate doesn’t have control on the versioning with Copy Team. By Default, it copies all the available file versions.
For bulk operations, use the script provided below.
1.2. Document Target URLs
- After creating the team structure in the target, record the Target URL.
- Create an Excel file listing each Source URL alongside its corresponding Target URL for the Input file.
1.3. Execute Copy Operations
- Run Copy Structure and Site for each Source URL and its corresponding Target URL.
- For bulk operations, follow the script provided below.
1.4. Lock the sites in Source
- Ensure that the source sites are locked after the migration process.
2. Copy Team site structure in bulk
- Create an Input text file and enter the Team Display Name as show below:
- With Data
==================================================
$source = Connect-Tenant -Domain <<SourceDomain.onmicrosoft.com>> -Browser
$destination = Connect-Tenant -Domain <<TargetDomain.onmicrosoft.com>> -Browser
$tracefile="Migrate_Teams_SourceToTenant$(get-date -format 'MMddyyyyHHMMss').log"
Start-Transcript $tracefile
$Teamslist = Import-Csv -Path "C:\Script\Input.csv"
Foreach ($SiteName in $Teamslist)
{
$TeamsName = "$($SiteName.'TeamDisplayName')"
$team = Get-Team -Name "$TeamsName" -Tenant $source
Write-Host "Migrating Team $TeamsName to Destination Tenant in Progress..." -ForegroundColor Green
Copy-Team -Team $team -DestinationTenant $destination
}
Stop-Transcript
===========================================================================
- Without Data
===================================================
$source = Connect-Tenant -Domain SourceDomain.onmicrosoft.com -Browser -DisableSSO
$destination = Connect-Tenant -Domain TargetDomain.onmicrosoft.com -Browser -DisableSSO
# Start Transcript
Start-Transcript -Path "D:\Script\BulkCopyTeamWITHOUTData\BulkCopyTranscript.txt" -Append
$Teamslist = Import-Csv -Path "D:\Script\BulkCopyTeamWITHOUTData\Input.csv"
foreach($SiteName in $Teamslist)
{
$options = New-TeamCopyOptions -NoFiles
$TeamsName = "$($SiteName.'TeamDisplayName')"
$Getteam = Get-Team -Name "$TeamsName" -Tenant $source
Write-Host "Migrating Team $TeamsName to Destination Tenant WITHOUT DATA in Progress..." -ForegroundColor Green
Copy-Team -Team $Getteam -DestinationTenant $destination -CopyOptions $options
}
Stop-Transcript
3. Copy Site (Structure and Content) in bulk
================================================
Import-Module ShareGate
$csvFile = "D:\script\CopyContent\Input.csv"
$table = Import-Csv $csvFile -Delimiter ","
$sourceconnection = Connect-Site -Url https://SourceDomain.sharepoint.com/sites/TestTeambyGaurav -Browser -DisableSSO
$destinationconnection = Connect-Site -Url https://TargetDomain.sharepoint.com/sites/TestTeambyGaurav -Browser -DisableSSO
$copysettings = New-CopySettings -OnContentItemExists Skip
Set-Variable srcSite, dstSite
foreach ($row in $table) {
# Clear-Variable srcSite
Clear-Variable dstSite
$srcSite = Connect-Site -Url $row.SourceSite -UseCredentialsFrom $sourceconnection
$dstSite = Connect-Site -Url $row.DestinationSite -UseCredentialsFrom $destinationconnection
Copy-Site -Site $srcSite -DestinationSite $dstSite -Merge -Subsites -VersionLimit 1 -CopySettings $copysettings
======================================================
Note:
- Input file should be in the format as mentioned below:
- -VersionLimit 1: Limits the number of versions to copy
- $copysettings = New-CopySettings -OnContentItemExists Skip: Creates a new copy settings object that specific to skip items if they already exist in the destination.
- For incremental migration: Replace “Skip” with “IncrementalUpdate” in previous step
4. Lock the Sites in Source
==============================================================
Connect-SPOService -Url https://SourceDomain-admin.sharepoint.com
Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
$siteUrlsFile = "C:\Sites.txt"
$siteUrls = Get-Content -Path $siteUrlsFile
# Loop through each site and set the lock state to ReadOnly
foreach ($siteUrl in $siteUrls)
Set-SPOSite -Identity $siteUrl -LockState ReadOnly
Write-Host "Site locked: $siteUrl"
}
============================================================
5. Migration of Private Channels:
- Private Channels have their own SharePoint sites.
- During the Team structure creation in step 1.1, Private Channels will be migrated to the target. However, their content will not be copied since they have separate SharePoint sites.
- Create an input file mapping Source Private Channels to their corresponding Target Private Channels, and follow the steps outlined in Step 3.
- Lock the Private Channels as described in Step 4.