Forum Discussion
Copy/move folders from SharePoint site to OneDrive user using Powershell
Hi community members! Hope you are doing allright!
I'm hoping one of you is willing to help me out a bit. I will try to describe my case as clear as possible:
A customer of mine is using an archive-user in their Microsoft 365 tenant. It's a user with a OneDrive (plan 2) license added to it. The storage of this user has been extended up to 5 TB. So far, so good, as the customer know how to use this archive user and how to manage it.
This customer has a lot (and I do mean a lot!) of Teams groups and SharePoint sites which contains lots of (old) data. This customer wants to reduce their Extra File Storage costs in SharePoint (which makes sense), and asked me to help out with migrating/moving the data in some of the groups to this archive user.
Now, I know how to copy/move folders or files in the webbrowser and/or file explorer from SharePoint to OneDrive, but these ways are just to slow and/or not sufficient enough.
So, I was looking in to Powershell as a solution to move/copy folders from a SharePoint site to the OneDrive user.
I've found some scripts, which might be useful, but I'm getting stuck as how to add the URL's of both the SharePoint site and the OneDrive user.
These are the scripts I've found so far:
- https://pnp.github.io/powershell/cmdlets/Copy-PnPFolder.html
- https://pnp.github.io/powershell/cmdlets/Copy-PnPFile.html
If somebody is able to help me out how I can (easily ;P) copy/move data from a SharePoint site to OneDrive, or provide me with a script that I could use, I would really be obliged!
Thanks in advance!
Yeah! just change from Copy-PnPFile to Move-PnPFile.
You can also make the code more efficient using Move-PnPFolder. But it doesn't really like large folders in my experience
# Connect to the source site collection $sourceSiteUrl = "https://yourtenant.sharepoint.com/sites/SourceSiteCollection" Connect-PnPOnline -Url $sourceSiteUrl -Interactive # Connect to the target site collection $targetSiteUrl = "https://yourtenant.sharepoint.com/sites/TargetSiteCollection" Connect-PnPOnline -Url $targetSiteUrl -Interactive # Define source and target library and folder paths $sourceLibrary = "Documents" $targetLibrary = "Documents" # Get all items from the source library $sourceItems = Get-PnPListItem -List $sourceLibrary -PageSize 2000 foreach ($item in $sourceItems) { $sourceFileUrl = $item.FieldValues["FileRef"] $targetFileUrl = $sourceFileUrl -replace "$sourceLibrary", $targetLibrary $targetFileUrl = $targetFileUrl -replace $sourceSiteUrl, $targetSiteUrl try { Move-PnPFile -SourceUrl $sourceFileUrl -TargetUrl $targetFileUrl -Force -OverwriteIfAlreadyExists Write-Host "Moved: $sourceFileUrl to $targetFileUrl" } catch { Write-Host "Failed to move: $sourceFileUrl" } }
So I would approach this in a different way and just use SharePoint Archiving and Backup instead. Just Archive the Files/Sites that is not in use and retrieve them when needed instead of being in someone's OneDrive. Also using archiving the storage is 75% Cheaper
# Install the PnP PowerShell module if not already installed Install-Module -Name "PnP.PowerShell" -Force -SkipPublisherCheck # Connect to the source SharePoint site $sourceSiteUrl = "https://yourtenant.sharepoint.com/sites/SourceSite" Connect-PnPOnline -Url $sourceSiteUrl -Interactive # Store the connection for later use $sourceConnection = Get-PnPConnection # Connect to the destination SharePoint site $destinationSiteUrl = "https://yourtenant.sharepoint.com/sites/DestinationSite" Connect-PnPOnline -Url $destinationSiteUrl -Interactive # Store the connection for later use $destinationConnection = Get-PnPConnection # Define source and destination library and folder $sourceLibrary = "Documents" $sourceFolder = "FolderToMove" $destinationLibrary = "Documents" $destinationFolder = "FolderToMove" # Use the source connection Set-PnPConnection -Connection $sourceConnection # Get all files and subfolders in the source folder $files = Get-PnPFolderItem -FolderSiteRelativeUrl "$sourceLibrary/$sourceFolder" -ItemType File $subFolders = Get-PnPFolderItem -FolderSiteRelativeUrl "$sourceLibrary/$sourceFolder" -ItemType Folder # Copy each file to the destination folder foreach ($file in $files) { $sourceFileUrl = $file.ServerRelativeUrl $destinationFileUrl = $sourceFileUrl -replace $sourceSiteUrl, $destinationSiteUrl Set-PnPConnection -Connection $destinationConnection Copy-PnPFile -SourceUrl $sourceFileUrl -TargetUrl $destinationFileUrl -OverwriteIfAlreadyExists } # Copy each subfolder and its contents recursively function Copy-FolderContents { param ( [string]$currentFolderUrl ) # Get files and subfolders in the current folder $currentFiles = Get-PnPFolderItem -FolderSiteRelativeUrl $currentFolderUrl -ItemType File $currentSubFolders = Get-PnPFolderItem -FolderSiteRelativeUrl $currentFolderUrl -ItemType Folder # Copy each file foreach ($file in $currentFiles) { $sourceFileUrl = $file.ServerRelativeUrl $destinationFileUrl = $sourceFileUrl -replace $sourceSiteUrl, $destinationSiteUrl Set-PnPConnection -Connection $destinationConnection Copy-PnPFile -SourceUrl $sourceFileUrl -TargetUrl $destinationFileUrl -OverwriteIfAlreadyExists } # Recursively copy each subfolder foreach ($folder in $currentSubFolders) { $sourceFolderUrl = $folder.ServerRelativeUrl $destinationFolderUrl = $sourceFolderUrl -replace $sourceSiteUrl, $destinationSiteUrl Set-PnPConnection -Connection $destinationConnection New-PnPFolder -Name $folder.Name -Folder (Split-Path -Path $destinationFolderUrl -Parent) Copy-FolderContents -currentFolderUrl $sourceFolderUrl } } Copy-FolderContents -currentFolderUrl "$sourceLibrary/$sourceFolder"
- Koen_RealConnectionsCopper Contributor
NicolasKheirallah Thank you for your suggestion! In the script you've sent, I see that script is using a copy option. Is this also possible for moving? Or not?
I'm interested in this archiving solution, but how does this work exactly? Aside from that script? I mean, if any data is ever needed, how can this data be approached in userfriendly way? As in, would something like be also do-able for an end-user, or is this more a admin job?
If you have any more tips/tricks how to start setting up this SharePoint archiving solution, I'm really looking forward to your reaction!
Thanks in advance!Yeah! just change from Copy-PnPFile to Move-PnPFile.
You can also make the code more efficient using Move-PnPFolder. But it doesn't really like large folders in my experience
# Connect to the source site collection $sourceSiteUrl = "https://yourtenant.sharepoint.com/sites/SourceSiteCollection" Connect-PnPOnline -Url $sourceSiteUrl -Interactive # Connect to the target site collection $targetSiteUrl = "https://yourtenant.sharepoint.com/sites/TargetSiteCollection" Connect-PnPOnline -Url $targetSiteUrl -Interactive # Define source and target library and folder paths $sourceLibrary = "Documents" $targetLibrary = "Documents" # Get all items from the source library $sourceItems = Get-PnPListItem -List $sourceLibrary -PageSize 2000 foreach ($item in $sourceItems) { $sourceFileUrl = $item.FieldValues["FileRef"] $targetFileUrl = $sourceFileUrl -replace "$sourceLibrary", $targetLibrary $targetFileUrl = $targetFileUrl -replace $sourceSiteUrl, $targetSiteUrl try { Move-PnPFile -SourceUrl $sourceFileUrl -TargetUrl $targetFileUrl -Force -OverwriteIfAlreadyExists Write-Host "Moved: $sourceFileUrl to $targetFileUrl" } catch { Write-Host "Failed to move: $sourceFileUrl" } }