SOLVED

Copy/move folders from SharePoint site to OneDrive user using Powershell

Copper Contributor

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:

 

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!

4 Replies

@Koen_RealConnections 

 

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"

 

@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!

best response confirmed by Koen_RealConnections (Copper Contributor)
Solution

@Koen_RealConnections 

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"
    }
}

 

@NicolasKheirallah 

 

Forget to reach out back to you soon, but I was able to make it work with the answer(s) you replied. Thank you for your suggestions!

1 best response

Accepted Solutions
best response confirmed by Koen_RealConnections (Copper Contributor)
Solution

@Koen_RealConnections 

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"
    }
}

 

View solution in original post