0% found this document useful (0 votes)
33 views7 pages

Sharepoint Migration

This document outlines a PowerShell script for migrating a document library from one SharePoint site to another, preserving folder structure, metadata, and permissions. It includes parameters for source and destination site URLs, library names, and options for migrating permissions and versions. The script features functions for logging, creating folder structures, copying files with metadata, and handling permissions during the migration process.

Uploaded by

fb sannadi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views7 pages

Sharepoint Migration

This document outlines a PowerShell script for migrating a document library from one SharePoint site to another, preserving folder structure, metadata, and permissions. It includes parameters for source and destination site URLs, library names, and options for migrating permissions and versions. The script features functions for logging, creating folder structures, copying files with metadata, and handling permissions during the migration process.

Uploaded by

fb sannadi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 7

# SharePoint Online Document Library Migration Script

# This script migrates a document library from one SharePoint site to another
# while preserving folder structure, metadata, and permissions

#Requires -Modules PnP.PowerShell

param(
[Parameter(Mandatory=$true)]
[string]$SourceSiteUrl,

[Parameter(Mandatory=$true)]
[string]$DestinationSiteUrl,

[Parameter(Mandatory=$true)]
[string]$SourceLibraryName,

[Parameter(Mandatory=$true)]
[string]$DestinationLibraryName,

[Parameter(Mandatory=$false)]
[switch]$MigratePermissions = $true,

[Parameter(Mandatory=$false)]
[switch]$MigrateVersions = $false,

[Parameter(Mandatory=$false)]
[string]$LogPath = ".\SharePointMigration.log"
)

# Function to write log messages


function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logMessage = "[$timestamp] [$Level] $Message"
Write-Host $logMessage
Add-Content -Path $LogPath -Value $logMessage
}

# Function to create folder structure recursively


function Create-FolderStructure {
param(
[Microsoft.SharePoint.Client.Folder]$SourceFolder,
[string]$DestinationPath,
[Microsoft.SharePoint.Client.ClientContext]$DestContext
)

try {
# Get subfolders from source
$subFolders = Get-PnPFolderItem -FolderSiteRelativeUrl
$SourceFolder.ServerRelativeUrl -ItemType Folder

foreach ($subFolder in $subFolders) {


$newFolderPath = "$DestinationPath/$($subFolder.Name)"

Write-Log "Creating folder: $newFolderPath"

# Create folder in destination


try {
Add-PnPFolder -Name $subFolder.Name -Folder $DestinationPath -
ErrorAction SilentlyContinue
Write-Log "Successfully created folder: $($subFolder.Name)"

# Recursively create subfolders


Create-FolderStructure -SourceFolder $subFolder -DestinationPath
$newFolderPath -DestContext $DestContext
}
catch {
Write-Log "Error creating folder $($subFolder.Name): $
($_.Exception.Message)" -Level "ERROR"
}
}
}
catch {
Write-Log "Error in Create-FolderStructure: $($_.Exception.Message)" -Level
"ERROR"
}
}

# Function to copy files with metadata


function Copy-FilesWithMetadata {
param(
[string]$SourceFolderPath,
[string]$DestinationFolderPath
)

try {
# Get files from source folder
$files = Get-PnPFolderItem -FolderSiteRelativeUrl $SourceFolderPath -
ItemType File

foreach ($file in $files) {


Write-Log "Copying file: $($file.Name)"

try {
# Download file from source
$tempFile = [System.IO.Path]::GetTempFileName()
Get-PnPFile -Url $file.ServerRelativeUrl -Path (Split-Path
$tempFile) -Filename (Split-Path $tempFile -Leaf) -AsFile

# Connect to destination to upload


Connect-PnPOnline -Url $DestinationSiteUrl -Interactive

# Upload file to destination


$uploadResult = Add-PnPFile -Path $tempFile -Folder
$DestinationFolderPath -NewFileName $file.Name

# Get source file metadata


Connect-PnPOnline -Url $SourceSiteUrl -Interactive
$sourceFile = Get-PnPFile -Url $file.ServerRelativeUrl -AsListItem

# Copy metadata to destination file


Connect-PnPOnline -Url $DestinationSiteUrl -Interactive
$destFile = Get-PnPFile -Url $uploadResult.ServerRelativeUrl -
AsListItem

# Copy field values (excluding system fields)


$fieldsToSkip = @("ID", "Created", "Modified", "Author", "Editor",
"Version", "_UIVersion", "_UIVersionString", "Attachments", "GUID",
"WorkflowVersion", "ParentVersionString", "ParentLeafName", "DocIcon", "ServerUrl",
"EncodedAbsUrl", "BaseName", "MetaInfo", "Level", "IsCurrentVersion",
"ItemChildCount", "FolderChildCount", "SMTotalSize", "SMLastModifiedDate",
"SMTotalFileStreamSize", "SMTotalFileCount", "File_x0020_Type",
"HTML_x0020_File_x0020_Type", "Edit", "LinkTitleNoMenu", "LinkTitle",
"SelectTitle", "InstanceID", "Order", "FileRef", "FileDirRef",
"Last_x0020_Modified", "Created_x0020_Date", "File_x0020_Size", "FSObjType",
"SortBehavior", "PermMask", "PrincipalCount", "CheckedOutUserId", "UniqueId",
"SyncClientId", "ProgId", "ScopeId", "VirusStatus", "CheckedOutTitle",
"_CheckinComment", "LinkCheckedOutTitle", "Modified_x0020_By", "Created_x0020_By",
"owshiddenversion", "_Level", "_IsCurrentVersion", "ContentTypeId", "Title",
"ContentType")

foreach ($field in $sourceFile.FieldValues.Keys) {


if ($fieldsToSkip -notcontains $field -and $sourceFile[$field]
-ne $null) {
try {
Set-PnPListItem -List $DestinationLibraryName -Identity
$destFile.Id -Values @{$field = $sourceFile[$field]}
}
catch {
Write-Log "Could not copy field $field : $
($_.Exception.Message)" -Level "WARNING"
}
}
}

# Clean up temp file


Remove-Item $tempFile -Force -ErrorAction SilentlyContinue

Write-Log "Successfully copied file: $($file.Name)"


}
catch {
Write-Log "Error copying file $($file.Name): $
($_.Exception.Message)" -Level "ERROR"
}
}
}
catch {
Write-Log "Error in Copy-FilesWithMetadata: $($_.Exception.Message)" -Level
"ERROR"
}
}

# Function to copy permissions


function Copy-Permissions {
param(
[string]$SourceItemPath,
[string]$DestinationItemPath,
[string]$ItemType = "File" # File or Folder
)

if (-not $MigratePermissions) {
return
}

try {
Write-Log "Copying permissions for $ItemType : $SourceItemPath"
# Connect to source to get permissions
Connect-PnPOnline -Url $SourceSiteUrl -Interactive

if ($ItemType -eq "File") {


$sourceItem = Get-PnPFile -Url $SourceItemPath -AsListItem
} else {
$sourceItem = Get-PnPFolder -Url $SourceItemPath -Includes
ListItemAllFields
$sourceItem = $sourceItem.ListItemAllFields
}

# Check if item has unique permissions


if ($sourceItem.HasUniqueRoleAssignments) {
$roleAssignments = Get-PnPProperty -ClientObject $sourceItem -Property
RoleAssignments

# Connect to destination
Connect-PnPOnline -Url $DestinationSiteUrl -Interactive

if ($ItemType -eq "File") {


$destItem = Get-PnPFile -Url $DestinationItemPath -AsListItem
} else {
$destItem = Get-PnPFolder -Url $DestinationItemPath -Includes
ListItemAllFields
$destItem = $destItem.ListItemAllFields
}

# Break inheritance on destination item


Set-PnPListItemPermission -List $DestinationLibraryName -Identity
$destItem.Id -InheritPermissions:$false

# Copy each role assignment


foreach ($roleAssignment in $roleAssignments) {
$principal = $roleAssignment.Member
$roleDefinitions = $roleAssignment.RoleDefinitionBindings

foreach ($roleDef in $roleDefinitions) {


try {
if ($principal.PrincipalType -eq "User") {
Set-PnPListItemPermission -List $DestinationLibraryName
-Identity $destItem.Id -User $principal.LoginName -AddRole $roleDef.Name
} else {
Set-PnPListItemPermission -List $DestinationLibraryName
-Identity $destItem.Id -Group $principal.LoginName -AddRole $roleDef.Name
}
Write-Log "Applied permission: $($roleDef.Name) to $
($principal.LoginName)"
}
catch {
Write-Log "Error applying permission $($roleDef.Name) to $
($principal.LoginName): $($_.Exception.Message)" -Level "WARNING"
}
}
}
}
}
catch {
Write-Log "Error copying permissions: $($_.Exception.Message)" -Level
"ERROR"
}
}

# Function to recursively process folders


function Process-Folder {
param(
[string]$SourceFolderPath,
[string]$DestinationFolderPath
)

try {
Write-Log "Processing folder: $SourceFolderPath"

# Connect to source
Connect-PnPOnline -Url $SourceSiteUrl -Interactive

# Copy files in current folder


Copy-FilesWithMetadata -SourceFolderPath $SourceFolderPath -
DestinationFolderPath $DestinationFolderPath

# Copy folder permissions


Copy-Permissions -SourceItemPath $SourceFolderPath -DestinationItemPath
$DestinationFolderPath -ItemType "Folder"

# Get subfolders
$subFolders = Get-PnPFolderItem -FolderSiteRelativeUrl $SourceFolderPath -
ItemType Folder

foreach ($subFolder in $subFolders) {


$sourceSubFolderPath = $subFolder.ServerRelativeUrl
$destSubFolderPath = "$DestinationFolderPath/$($subFolder.Name)"

# Recursively process subfolder


Process-Folder -SourceFolderPath $sourceSubFolderPath -
DestinationFolderPath $destSubFolderPath
}
}
catch {
Write-Log "Error processing folder $SourceFolderPath : $
($_.Exception.Message)" -Level "ERROR"
}
}

# Main execution
try {
Write-Log "Starting SharePoint Library Migration"
Write-Log "Source: $SourceSiteUrl/$SourceLibraryName"
Write-Log "Destination: $DestinationSiteUrl/$DestinationLibraryName"

# Check if PnP PowerShell module is installed


if (-not (Get-Module -ListAvailable -Name PnP.PowerShell)) {
Write-Log "PnP.PowerShell module not found. Installing..." -Level "WARNING"
Install-Module -Name PnP.PowerShell -Force -AllowClobber
}

# Connect to source site


Write-Log "Connecting to source site..."
Connect-PnPOnline -Url $SourceSiteUrl -Interactive
# Verify source library exists
$sourceLibrary = Get-PnPList -Identity $SourceLibraryName -ErrorAction
SilentlyContinue
if (-not $sourceLibrary) {
throw "Source library '$SourceLibraryName' not found in $SourceSiteUrl"
}

# Connect to destination site


Write-Log "Connecting to destination site..."
Connect-PnPOnline -Url $DestinationSiteUrl -Interactive

# Check if destination library exists, create if not


$destLibrary = Get-PnPList -Identity $DestinationLibraryName -ErrorAction
SilentlyContinue
if (-not $destLibrary) {
Write-Log "Creating destination library: $DestinationLibraryName"
New-PnPList -Title $DestinationLibraryName -Template DocumentLibrary
}

# Get source library root folder


Connect-PnPOnline -Url $SourceSiteUrl -Interactive
$sourceRootFolder = Get-PnPList -Identity $SourceLibraryName | Get-PnPProperty
-Property RootFolder

# Create folder structure in destination


Write-Log "Creating folder structure..."
Connect-PnPOnline -Url $DestinationSiteUrl -Interactive
$destLibraryPath = $DestinationLibraryName

Connect-PnPOnline -Url $SourceSiteUrl -Interactive


Create-FolderStructure -SourceFolder $sourceRootFolder -DestinationPath
$destLibraryPath -DestContext $null

# Process root folder and all contents


Write-Log "Starting content migration..."
$sourceFolderPath = $sourceRootFolder.ServerRelativeUrl
Process-Folder -SourceFolderPath $sourceFolderPath -DestinationFolderPath
$destLibraryPath

# Copy library-level permissions if specified


if ($MigratePermissions) {
Write-Log "Copying library-level permissions..."
try {
Connect-PnPOnline -Url $SourceSiteUrl -Interactive
$sourceLib = Get-PnPList -Identity $SourceLibraryName

if ($sourceLib.HasUniqueRoleAssignments) {
Connect-PnPOnline -Url $DestinationSiteUrl -Interactive
$destLib = Get-PnPList -Identity $DestinationLibraryName

# Break inheritance
Set-PnPListPermission -Identity $DestinationLibraryName -
InheritPermissions:$false

# Copy permissions (this would need additional logic similar to


item permissions)
Write-Log "Library permissions copied (basic implementation)"
}
}
catch {
Write-Log "Error copying library permissions: $($_.Exception.Message)"
-Level "WARNING"
}
}

Write-Log "Migration completed successfully!"


}
catch {
Write-Log "Migration failed: $($_.Exception.Message)" -Level "ERROR"
throw
}

# Usage Examples:
<#
# Basic migration
.\SharePointMigration.ps1 -SourceSiteUrl
"https://tenant.sharepoint.com/sites/source" -DestinationSiteUrl
"https://tenant.sharepoint.com/sites/destination" -SourceLibraryName "Documents" -
DestinationLibraryName "MigratedDocuments"

# Migration without permissions


.\SharePointMigration.ps1 -SourceSiteUrl
"https://tenant.sharepoint.com/sites/source" -DestinationSiteUrl
"https://tenant.sharepoint.com/sites/destination" -SourceLibraryName "Documents" -
DestinationLibraryName "MigratedDocuments" -MigratePermissions:$false

# Migration with custom log path


.\SharePointMigration.ps1 -SourceSiteUrl
"https://tenant.sharepoint.com/sites/source" -DestinationSiteUrl
"https://tenant.sharepoint.com/sites/destination" -SourceLibraryName "Documents" -
DestinationLibraryName "MigratedDocuments" -LogPath "C:\Logs\Migration.log"
#>

You might also like