Managing files in SharePoint Online often requires moving large numbers of files between document libraries to reorganize content, optimize storage, or comply with governance policies. PnP PowerShell provides a seamless way to automate this process efficiently.
Key Considerations Before Moving Files
✔ Source and Destination Libraries – Ensure both libraries exist in the same site.
✔ Permissions – The user must have edit permissions on both libraries.
✔ Metadata Retention – Ensure file metadata is preserved after the move.
✔ Version History – Moving files does not retain version history; consider copying if needed.
Step 1: Connect to SharePoint Online
First, connect to your SharePoint Online site using PnP PowerShell.
$siteUrl = "https://yourtenant.sharepoint.com/sites/YourSite"
# Connect to SharePoint Online
Connect-PnPOnline -Url $siteUrl -Interactive
✔ Ensures authentication to perform file operations.
Step 2: Define Source and Destination Libraries
Specify the source and destination document libraries where files will be moved.
$sourceLibrary = "SourceDocuments"
$destinationLibrary = "DestinationDocuments"
✔ Adjust these names as per your SharePoint site.
Step 3: Retrieve and Move Files in Bulk
Use PnP PowerShell to fetch all files and move them to the destination.
# Get all files from the source library
$files = Get-PnPListItem -List $sourceLibrary -PageSize 2000
foreach ($file in $files) {
$fileUrl = $file.FieldValues["FileRef"] # Get the full file path
$fileName = $file.FieldValues["FileLeafRef"] # Get the file name
$destinationPath = "/sites/YourSite/$destinationLibrary/$fileName"
# Move the file
Move-PnPFile -ServerRelativeUrl $fileUrl -TargetUrl $destinationPath -Force
Write-Host "✅ Moved: $fileName"
}
✔ Moves all files while maintaining the folder structure.
Step 4: Handling Folder Structure
To move files along with folders, include a folder check before moving.
# Get all items (files and folders)
$items = Get-PnPListItem -List $sourceLibrary -PageSize 2000
foreach ($item in $items) {
$fileRef = $item.FieldValues["FileRef"]
$fileLeaf = $item.FieldValues["FileLeafRef"]
# Determine if the item is a folder
if ($item.FieldValues["FSObjType"] -eq 1) {
# Create the folder in the destination if it doesn’t exist
$folderPath = "/sites/YourSite/$destinationLibrary/$fileLeaf"
New-PnPFolder -Name $fileLeaf -List $destinationLibrary
Write-Host " Created Folder: $fileLeaf"
} else {
# Move the file while maintaining folder structure
$destinationPath = "/sites/YourSite/$destinationLibrary/$fileLeaf"
Move-PnPFile -ServerRelativeUrl $fileRef -TargetUrl $destinationPath -Force
Write-Host " Moved File: $fileLeaf"
}
}
✔ Ensures both files and folders are moved correctly.
Step 5: Preserve Metadata During Move
Since moving files removes modified dates, use a custom script to retain metadata.
foreach ($file in $files) {
$fileUrl = $file.FieldValues["FileRef"]
$fileName = $file.FieldValues["FileLeafRef"]
$modifiedBy = $file.FieldValues["Editor"].Email
$modifiedDate = $file.FieldValues["Modified"]
$destinationPath = "/sites/YourSite/$destinationLibrary/$fileName"
# Move the file
Move-PnPFile -ServerRelativeUrl $fileUrl -TargetUrl $destinationPath -Force
# Restore metadata
Set-PnPListItem -List $destinationLibrary -Identity $file.Id -Values @{
"Editor" = $modifiedBy
"Modified" = $modifiedDate
}
Write-Host " Moved and Restored Metadata: $fileName"
}
✔ Ensures last modified user and timestamp remain intact.
Step 6: Generate a Move Report
Create a CSV report to log file movement for audit purposes.
$report = @()
foreach ($file in $files) {
$fileUrl = $file.FieldValues["FileRef"]
$fileName = $file.FieldValues["FileLeafRef"]
$destinationPath = "/sites/YourSite/$destinationLibrary/$fileName"
# Log each file move
$report += [PSCustomObject]@{
FileName = $fileName
SourcePath = $fileUrl
DestinationPath = $destinationPath
Status = "Moved"
}
}
# Export report
$report | Export-Csv -Path "C:\SharePointFileMoveReport.csv" -NoTypeInformation
Write-Host "📄 Report Generated: C:\SharePointFileMoveReport.csv"
✔ Provides a detailed log of moved files.
Step 7: Delete Empty Folders in Source Library
Once files are moved, delete empty folders to clean up the source library.
$folders = Get-PnPListItem -List $sourceLibrary | Where-Object { $_.FieldValues["FSObjType"] -eq 1 }
foreach ($folder in $folders) {
$folderUrl = $folder.FieldValues["FileRef"]
Remove-PnPListItem -List $sourceLibrary -Identity $folder.Id -Recycle
Write-Host "🗑 Deleted Empty Folder: $folderUrl"
}
✔ Keeps your document library organized.