The first step in any migration project is to do the inventory and see what is the size of the data you have got which you are looking to migrate. For the simplicity, this post assumes you have already done this activity and have already planned new destination sites for your existing content. This means you have some excel sheet somewhere to identify where your content is going to reside in your migrated site and every existing site (in scope) have got at least a new home pointer if it qualifies for migration.
The project I was working on had 6 level of sites and subsites within a site collection, for simplicity we just consider one site collection in scope for this post and had finalised it will have max. 3 levels of site and a subsite initially after discussing it with business.
In this blog post, we will be migrating SharePoint 2010 and 2013 contents from on-premise to SharePoint Online (SPO) in our customer’s Office 365 tenant.

Creating Structure

After doing the magic of mapping an existing site collection, site and subsites; we came up with an excel sheet to have the mapping for our desired structure as shown below:




The above files will be used as a reference master sheet to create site structure before pulling the trigger for migrating contents. We will be using PowerShell script below to create the structure for our desired state within our new site collection.


[code language=”powershell”]
$url = “”
function CreateLevelOne(){
Connect-PnPOnline -Url $url -Credentials ‘O365-CLIENT-CREDENTIALS’
filter Get-LevelOne {
New-PnPWeb -Title $_.SiteName -Url $_.URL1 -Template BLANKINTERNETCONTAINER#0 -InheritNavigation -Description “Site Structure created as part of Migration”
Import-Csv C:\_temp\Level1.csv | Get-LevelOne
function CreateLevelTwo(){
filter Get-LevelTwo {
$connectUrl = $url + $_.Parent
Connect-PnPOnline -Url $connectUrl -Credentials ‘O365-CLIENT-CREDENTIALS’
New-PnPWeb -Title $_.SiteName -Url $_.URL2 -Template BLANKINTERNETCONTAINER#0 -InheritNavigation -Description “Site Structure created as part of Migration”
Import-Csv C:\_temp\Level2.csv | Get-LevelTwo
function CreateLevelThree(){
filter Get-LevelThree {
$connectUrl = $url + $_.GrandPrent + ‘/’ + $_.Parent
Connect-PnPOnline -Url $connectUrl -Credentials ‘O365-CLIENT-CREDENTIALS’
New-PnPWeb -Title $_.SiteName -Url $_.URL3 -Template BLANKINTERNETCONTAINER#0 -InheritNavigation -Description “Site Structure created as part of Migration”
Import-Csv C:\_temp\Level3.csv | Get-LevelThree

Migrating Contents

Once you have successfully created your site structure, this is the time now to start migrating contents to the newly created structure as per the mapping you have identified earlier. CSV file format looks like below:

Final step is to execute PowerShell script and migrate content using ShareGate commands from your source site to your destination site (as defined in your mapping file above)


[code language=”powershell”]
# folder where files will be produced
$folderPath = “C:\_Kloud\SGReports\”
$folderPathBatches = “C:\_Kloud\MigrationBatches\”
filter Migrate-Content {
# URLs for source and destination
$urlDes = $_.DesintationURL
$urlSrc = $_.SourceURL
# file where migration log will be added again each run of this script
$itemErrorFolderPath = $folderPath + ‘SG-Migration-Log-Webs.csv’
# migration settings used by ShareGate commands
$copysettings = New-CopySettings -OnContentItemExists IncrementalUpdate -VersionOrModerationComment “updated while migration to Office 365”
$pwdDest = ConvertTo-SecureString “your-user-password” -AsPlainText -Force
$siteDest = Connect-Site -Url $urlDes -Username your-user-name -Password $pwdDest
$listsToCopy = @()
$siteSrc = Connect-Site -Url $urlSrc
$listsInSrc = Get-List -Site $siteSrc
foreach ($list in $listsInSrc)
if ($list.Title -ne “Content and Structure Reports” -and
$list.Title -ne “Form Templates” -and
$list.Title -ne “Master Page Gallery” -and
$list.Title -ne “Web Part Gallery” -and
$list.Title -ne “Pages” -and
$list.Title -ne “Style Library” -and
$list.Title -ne “Workflow Tasks”){
$listsToCopy += $list
# building a log entry with details for migration run
$date = Get-Date -format d
$rowLog = ‘”‘ + $siteSrc.Address + ‘”,”‘ + $siteSrc.Title + ‘”,”‘ + $listsInSrc.Count + ‘”,”‘ + $siteDest.Address + ‘”,”‘ + $siteDest.Title + ‘”,”‘ + $listsToCopy.Count + ‘”,”‘ + $date + ‘”‘
$rowLog | Out-File $itemErrorFolderPath -Append -Encoding ascii
Write-Host Copying $listsToCopy.Count out of $listsInSrc.Count lists and libraries to ‘(‘$siteDest.Address’)’
#Write-Host $rowLog
$itemLogFolderPath = $folderPath + $siteSrc.Title + ‘.csv’
#Write-Host $itemLogFolderPath
$result = Copy-List -List $listsToCopy -DestinationSite $siteDest -CopySettings $copysettings -InsaneMode -NoCustomPermissions -NoWorkflows
Export-Report $result -Path $itemLogFolderPath
function Start-Migration($batchFileName)
$filePath = $folderPathBatches + $batchFileName
Import-Csv $filePath | Migrate-Content
Start-Migration -batchFileName “MG-Batch.csv”


In this blog post, we had used a silent mode of ShareGate using which we can run in parallel multiple migration jobs from the different workstations (depending on your ShareGate licensing).
For a complete list of ShareGate PowerShell commands, you can refer a list at URL.
I hope you have found this post useful to create a site structure and migrate contents (list/libraries) to content’s new home inside SharePoint Online.

Office 365, PowerShell, SharePoint
, , ,