PowerShell – SharePoint – Move folders between site collections, subsites, and libraries

There are several ways to move data between libraries in SharePoint.

One of them is using UI. While this method has become better over the years, it’s still slow and buggy at times. Just recently I had an issue where SharePoint UI would not move more than 20 folders, it would time out. 

Another method is using PowerShell to do such a task. Out there you can definitely find scripts that would move data; however, you need to provide all prerequisite information and do it correctly. A typo or a library display name vs different internal name would leave you scratching your head for quite some time. If you do use subsites in your site collections, then things become progressively more complicated.

To address most of the struggle I decided to create a script that will do it all. The goal was to automate everything where an admin would only need to select a location by selecting options. In a nutshell, this is how it can move data from Library A to Library B:

  • Everything from Library A to Library B
  • Everything from Library A to Folder in Library B
  • Folder and its content from Library A to Library B
  • Folder and its content from Library A to Folder in Library B
  • Content of the folder from Library A to Library B
  • Content of the folder from Library A to Folder in Library B

All these options above should cover pretty much every scenario you can possibly have.

Pros:

  • The script is streamlined, so it’s hard to make any mistake or select wrong location.
  • When selecting a folder, the script checks if it exists.
  • Works with site collections and subsites.

Cons:

  • When moving data between subsites and site collections, the Modified value will be refreshed
  • The script does not move files unless they are within the folder(s) that are being moved.
#---------------------------------------------------[Variables]---------------------------------------------------
$AdminSiteUrl = "https://contoso-admin.sharepoint.com/"

$Exclusions = @(
    "https://contoso.sharepoint.com/portals/hub",
    "https://contoso-my.sharepoint.com/",
    "https://contoso.sharepoint.com/portals/Community",
    "https://contoso.sharepoint.com/search",
    "https://contoso.sharepoint.com/portals/contoso-Internal-Communications"
)
#---------------------------------------------------[Function 1]--------------------------------------------------
Function Get-CollectionType {

    Begin{}

    Process{
        # Site Collection types
        $Type = @()
        $Item1 = new-object PSObject -Property @{Number = 1; Type = 'Site collection'; Value = @('STS#0','EHS#1')}
        $Item2 = new-object PSObject -Property @{Number = 2; Type = 'Office 365 group'; Value = @('GROUP#0')}
        $Item3 = new-object PSObject -Property @{Number = 3; Type = 'Project Online'; Value = @('PWA#0')}
        $Type += $Item1,$Item2,$Item3
        $Type | ft Number,Type | Out-Host

        # Choose Site Collection type
        Do {
            Try {
                $Num = $true
                [int]$SelectedInput = Read-host "Select SharePoint site collection type by typing its number"
            }
            Catch {$Num = $false}
        }
        Until (($SelectedInput -gt 0 -and $SelectedInput -le $Type.count) -and $Num -eq $true)
        $SelectedType = $Type[[int]$SelectedInput - 1].Value
        $SelectedType
    }

    End{}

}
#---------------------------------------------------[Function 2]--------------------------------------------------
Function Get-SiteCollection {

    param (
        [Parameter(Mandatory=$True)]$SelectedType
    )

    Begin{}

    Process{
        # Get all Site Collections filtered by the choice above
        $SiteCollections = Get-SPOSite | Where-Object {($Exclusions -cnotcontains $_.Url) -and ($SelectedType -contains $_.Template)} |
        ForEach -Begin { $i = 1 } -Process {
            Add-Member -InputObject $_ -MemberType NoteProperty -Name Number -Value ($i++) -PassThru -Force
        }
        $SiteCollections | ft Number,Url | Out-Host

        # Choose Site Collection
        Do {
            Try {
                $Num = $true
                [int]$SelectedInput = Read-host "Select SharePoint site collection by typing its number"
            }
            Catch {$Num = $false}
        }
        Until (($SelectedInput -gt 0 -and $SelectedInput -le $SiteCollections.count) -and $Num -eq $true)
        $SelectedSiteCollection = $SiteCollections[[int]$SelectedInput - 1].Url
        $SelectedSiteCollection
    }

    End{}

}
#---------------------------------------------------[Function 3]--------------------------------------------------
Function Get-SiteType {

    Begin{}

    Process{
        # Site types
        $ChoiceBetweenMainAndSubsites = @()
        $Item1 = new-object PSObject -Property @{Number = 1; Type = 'Main Site'}
        $Item2 = new-object PSObject -Property @{Number = 2; Type = 'Subsites'}
        $ChoiceBetweenMainAndSubsites += $Item1,$Item2
        $ChoiceBetweenMainAndSubsites | ft Number,Type | Out-Host

        # Choose Site type
        Do {
            Try {
                $Num = $true
                [int]$SelectedInput = Read-host "Choose between a Main site or Subsites by typing the number"
            }
            Catch {$Num = $false}
        }
        Until (($SelectedInput -gt 0 -and $SelectedInput -le $ChoiceBetweenMainAndSubsites.count) -and $Num -eq $true)
        $SelectedSiteType = $ChoiceBetweenMainAndSubsites[[int]$SelectedInput - 1].Type
        $SelectedSiteType
    }

    End{}

}
#---------------------------------------------------[Function 4]--------------------------------------------------
Function Get-SiteAndLibrary {

    param (
        [Parameter(Mandatory=$True)]$SelectedSiteType
    )

    Begin{}

    Process{
        If ($SelectedSiteType -eq 'Main Site') {
            # List libraries
            $Libraries = Get-PnPLIst | Where-Object {$_.BaseType -eq "DocumentLibrary"} | 
            ForEach -Begin { $i = 1 } -Process {
                Add-Member -InputObject $_ -MemberType NoteProperty -Name Number -Value ($i++) -PassThru -Force
            }
            $SelectedSubsite = $null
            $Libraries | ft Number,Title | Out-Host
        }

        ElseIf ($SelectedSiteType -eq 'Subsites') {
            # Get all Subsites
            $Subsites = Get-PnPSubWebs -Recurse |
            ForEach -Begin { $i = 1 } -Process {
                Add-Member -InputObject $_ -MemberType NoteProperty -Name Number -Value ($i++) -PassThru -Force
            }
            $Subsites | ft Number,ServerRelativeUrl | Out-Host

            # Exit if no subsites found
            If ($Subsites.Count -eq 0) {
                Write-host `n"No subsites found, exiting the script" -ForegroundColor Red
                Exit
            }

            # Choose Subsite
            Do {
                Try {
                    $Num = $true
                    [int]$SelectedInput = Read-host "Select subsite by typing its number"
                }
                Catch {$Num = $false}
            }
            Until (($SelectedInput -gt 0 -and $SelectedInput -le $Subsites.count) -and $Num -eq $true)
            $SelectedSubsite = $Subsites[[int]$SelectedInput - 1].ServerRelativeUrl

            # List libraries
            $Libraries = Get-PnPLIst -Web $SelectedSubsite | Where-Object {$_.BaseType -eq "DocumentLibrary"} | 
            ForEach -Begin { $i = 1 } -Process {
                Add-Member -InputObject $_ -MemberType NoteProperty -Name Number -Value ($i++) -PassThru -Force
            }
        
            $Libraries | 
            ForEach -Process {
                Add-Member -InputObject $_ -MemberType NoteProperty -Name Url -Value ($_.RootFolder.ServerRelativeUrl.Substring(1))
            }

            $Libraries | ft Number,Title,Url | Out-Host
        }

        
        # Exit if no libraries found
        If ($Libraries.Count -eq 0) {
            Write-host `n"No libraries found, exiting the script" -ForegroundColor Red
            Exit
        }

        # Choose Library
        Do {
            Try {
                $Num = $true
                [int]$SelectedInput = Read-host "Choose a library by typing the number"
            }
            Catch {$Num = $false}
        }
        Until (($SelectedInput -gt 0 -and $SelectedInput -le $Libraries.count) -and $Num -eq $true)
        $SelectedLibrary = ($Libraries[[int]$SelectedInput - 1].RootFolder.ServerRelativeUrl).TrimStart("/")

        If ($SelectedSiteType -eq 'Subsites') {
            $SelectedLibrary -match $SelectedSubsite.TrimStart("/")+"/(?<LibName>.*)"    
            $SelectedLibrary = $Matches['LibName']
        }

        $SiteAndLibraryObject = new-object PSObject -Property @{Site = $SelectedSubsite; Library = $SelectedLibrary}
        $SiteAndLibraryObject
    }

    End{}

}
#---------------------------------------------------[Function 5]--------------------------------------------------
Function Get-MoveActionType {

    Begin{}

    Process{
        # Move action types
        $Type = @()
        $Item1 = new-object PSObject -Property @{Number = 1; Move = 'Everything from Library A'; ValueFrom = 'MoveFrom1'; To = "Library B"; ValueTo = 'MoveTo1'}
        $Item2 = new-object PSObject -Property @{Number = 2; Move = 'Everything from Library A'; ValueFrom = 'MoveFrom1'; To = "Folder in Library B"; ValueTo = 'MoveTo2'}
        $Item3 = new-object PSObject -Property @{Number = 3; Move = 'Folder and its content from Library A'; ValueFrom = 'MoveFrom2'; To = "Library B"; ValueTo = 'MoveTo1'}
        $Item4 = new-object PSObject -Property @{Number = 4; Move = 'Folder and its content from Library A'; ValueFrom = 'MoveFrom2'; To = "Folder in Library B"; ValueTo = 'MoveTo2'}
        $Item5 = new-object PSObject -Property @{Number = 5; Move = 'Content of the folder from Library A'; ValueFrom = 'MoveFrom3'; To = "Library B"; ValueTo = 'MoveTo1'}
        $Item6 = new-object PSObject -Property @{Number = 6; Move = 'Content of the folder from Library A'; ValueFrom = 'MoveFrom3'; To = "Folder in Library B"; ValueTo = 'MoveTo2'}
        $Type += $Item1,$Item2,$Item3,$Item4,$Item5,$Item6
        $Type | ft Number,Move,To | Out-Host

        # Choose Move action type
        Do {
            Try {
                $Num = $true
                [int]$SelectedInput = Read-host "Select move action by typing its number"
            }
            Catch {$Num = $false}
        }
        Until (($SelectedInput -gt 0 -and $SelectedInput -le $Type.count) -and $Num -eq $true)

        $SelectedMoveType = $Type[[int]$SelectedInput - 1].Value
        
        $SelectedMoveType = new-object PSObject -Property @{ActionFrom = $Type[[int]$SelectedInput - 1].ValueFrom; ActionTo = $Type[[int]$SelectedInput - 1].ValueTo}
        $SelectedMoveType
    }

    End{}

}
#---------------------------------------------------[Function 6]--------------------------------------------------
Function Move-Folder {

    param (
        [Parameter(Mandatory=$True)]$AdminSiteUrl,
        [Parameter(Mandatory=$True)]$FolderSourceUrl,
        [Parameter(Mandatory=$True)]$FolderTargetUrl
    )

    Begin {}

    Process {
        Try{
            # Setup the context
            $Context = New-Object Microsoft.SharePoint.Client.ClientContext($AdminSiteURL)
            $Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserCredential.Username, $UserCredential.Password)
     
            # Move the Folder
            $MoveCopyOpt = New-Object Microsoft.SharePoint.Client.MoveCopyOptions
            [Microsoft.SharePoint.Client.MoveCopyUtil]::MoveFolder($Context, $FolderSourceURL, $FolderTargetURL, $MoveCopyOpt)
            $Context.ExecuteQuery()
 
            Write-host "Successfully moved -" $FolderTargetURL -ForegroundColor Green
        }
        Catch {
            write-host "Not moved -" $_.Exception.Message -ForegroundColor Red
        }
    }

    End {}
} 
#---------------------------------------------------[Function 7]--------------------------------------------------
Function Check-Folder {

    [CmdletBinding(DefaultParameterSetName="MainSiteSet")]

    param (
        [Parameter(ParameterSetName="MainSiteSet", Mandatory=$True)] $Title,
        [Parameter(ParameterSetName="SubsiteSet", Mandatory=$True)] $SubsiteUrl,
        [Parameter(ParameterSetName="SubsiteSet", Mandatory=$True)] $SubsiteTitle
    )

    Begin {}

    Process {
        Do {
            Try {
                $FolderName = Read-host `n"Provide the path of the folder"
                $FolderName = $FolderName.TrimEnd("/").TrimStart("/")
                If ($PSCmdlet.ParameterSetName -eq "MainSiteSet") {
                    
                    $GetFolder = Get-PnPFolder -Url ($Title + "/" + $FolderName) -ErrorAction Stop
                }
                ElseIf ($PSCmdlet.ParameterSetName -eq "SubsiteSet") {
                    $GetFolder = Get-PnPFolder -Web $SubsiteUrl -Url ($SubsiteTitle + "/" + $FolderName) -ErrorAction Stop
                }

                
            }
            Catch {
                Write-Host `n"Cannot find the folder!" -ForegroundColor Red
            }
        }
        Until ($GetFolder -ne $null)
        Write-Host `n"Found the folder!"`n -ForegroundColor Green
        $SelectedFolder = new-object PSObject -Property @{FolderPath = $FolderName; FolderName = $GetFolder.Name}
        $SelectedFolder
    }

    End {}
}
#-----------------------------------------------------[Script]----------------------------------------------------

# Start timer
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()

# Connect to SharePoint Online Admin
Connect-PnPOnline -Url $AdminSiteUrl -Credentials $UserCredential

Write-host `n"Select a Move action by typing its number:" -ForegroundColor Green

# Call Function 5
$SelectedMoveActionType = Get-MoveActionType

Write-host `n"The following questionairy applies to a Source Location:" -ForegroundColor Yellow

# Call Function 1 (From)
$SelectedTypeFrom = Get-CollectionType

# Call Function 2 (From)
$SelectedSiteCollectionFrom = Get-SiteCollection -SelectedType $SelectedTypeFrom

If ($SelectedSiteCollectionFrom -match '\/$') {
    $SelectedSiteCollectionFrom = $SelectedSiteCollectionFrom.TrimEnd("/")
}

# Connect to Site Collection (From)
Connect-PnPOnline -Url $SelectedSiteCollectionFrom -Credentials $UserCredential

# Call Function 3 (From)
$SelectedSiteTypeFrom = Get-SiteType

# Call Function 4 (From)
$SelectedLibraryFrom = Get-SiteAndLibrary -SelectedSiteType $SelectedSiteTypeFrom

# Check if subsite is null and/or remove "/" from the beginning of subsite
If ($SelectedLibraryFrom.Site -ne $null) {
    If ($SelectedLibraryFrom.Site -match '^\/') {
        $SelectedSubsiteFrom = $SelectedLibraryFrom.Site.Substring(1)
    }
    Else {
        $SelectedSubsiteFrom = $SelectedLibraryFrom.Site
    }
}
Else {
    $SelectedSubsiteFrom = $SelectedLibraryFrom.Site
}

# Ask for "From" folder if selected move type requires it
If ($SelectedMoveActionType.ActionFrom -ne 'MoveFrom1') {
    If ($SelectedSubsiteFrom -ne $null) {
        $FolderFrom = Check-Folder -SubsiteUrl $SelectedSubsiteFrom -SubsiteTitle $SelectedLibraryFrom.Library
    }
    ElseIf ($SelectedSubsiteFrom -eq $null) {
        $FolderFrom = Check-Folder -Title $SelectedLibraryFrom.Library
    }
}

Write-host "The following questionairy applies to a Target Location:" -ForegroundColor Cyan

# Call Function 1 (To)
$SelectedTypeTo = Get-CollectionType

# Call Function 2 (To)
$SelectedSiteCollectionTo = Get-SiteCollection -SelectedType $SelectedTypeTo

If ($SelectedSiteCollectionTo -match '\/$') {
    $SelectedSiteCollectionTo = $SelectedSiteCollectionTo.TrimEnd("/")
}

# Connect to Site Collection (To)
Connect-PnPOnline -Url $SelectedSiteCollectionTo -Credentials $UserCredential

# Call Function 3 (To)
$SelectedSiteTypeTo = Get-SiteType

# Call Function 4 (To)
$SelectedLibraryTo = Get-SiteAndLibrary -SelectedSiteType $SelectedSiteTypeTo

# Check if subsite is null and/or remove "/" from the beginning of subsite
If ($SelectedLibraryTo.Site -ne $null) {
    If ($SelectedLibraryTo.Site -match '^\/') {
        $SelectedSubsiteTo = $SelectedLibraryTo.Site.Substring(1)
    }
    Else {
        $SelectedSubsiteTo = $SelectedLibraryTo.Site
    }
}
Else {
    $SelectedSubsiteTo = $SelectedLibraryTo.Site
}

# Ask for "To" folder if selected move type requires it
If ($SelectedMoveActionType.ActionTo -eq 'MoveTo2') {
    If ($SelectedSubsiteTo -ne $null) {
        $FolderTo = Check-Folder -SubsiteUrl $SelectedSubsiteTo -SubsiteTitle $SelectedLibraryTo.Library
    }
    ElseIf ($SelectedSubsiteTo -eq $null) {
        $FolderTo = Check-Folder -Title $SelectedLibraryTo.Library
    }
}

# Connect to Site Collection (From)
Connect-PnPOnline -Url $SelectedSiteCollectionFrom -Credentials $UserCredential

# When "From" is main site and "To" is main site
If (($SelectedSubsiteFrom -eq $null) -and ($SelectedSubsiteTo -eq $null)) {
    
    # Move Option 1
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 2
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 3
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }
      
    # Move Option 4
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }

    # Move Option 5
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 6
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name

            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }
}

# When "From" is main site and "To" is subsite
ElseIf (($SelectedSubsiteFrom -eq $null) -and ($SelectedSubsiteTo -ne $null)) {
    # Move Option 1
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 2
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 3
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }
      
    # Move Option 4
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }

    # Move Option 5
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 6
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }
}

# When "From" is subsite and "To" is main site
ElseIf (($SelectedSubsiteFrom -ne $null) -and ($SelectedSubsiteTo -eq $null)) {
    
    # Move Option 1
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 2
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 3
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }
  
    # Move Option 4
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }

    # Move Option 5
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 6
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }
}

# When "From" is subsite and "To" is subsite
ElseIf (($SelectedSubsiteFrom -ne $null) -and ($SelectedSubsiteTo -ne $null)) {
    
    # Move Option 1
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 2
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom1') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl $SelectedLibraryFrom.Library -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 3
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }
  
    # Move Option 4
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom2') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath
        $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $FolderFrom.FolderName
        Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
    }

    # Move Option 5
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo1')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryTo.Library + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }

    # Move Option 6
    If (($SelectedMoveActionType.ActionFrom -eq 'MoveFrom3') -and ($SelectedMoveActionType.ActionTo -eq 'MoveTo2')) {
        $Folders = Get-PnPFolderItem -Web $SelectedSubsiteFrom -FolderSiteRelativeUrl ($SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath) -ItemType Folder| Where-Object {$_.Name -ne "Forms" -and $_.Name -ne "Document"}
        ForEach ($Folder in $Folders) {
            $FolderSourceURL = $SelectedSiteCollectionFrom + "/" + $SelectedSubsiteFrom + "/" + $SelectedLibraryFrom.Library + "/" + $FolderFrom.FolderPath + "/" + $Folder.Name
            $FolderTargetURL = $SelectedSiteCollectionTo + "/" + $SelectedSubsiteTo + "/" + $SelectedLibraryTo.Library + "/" + $FolderTo.FolderPath + "/" + $Folder.Name
            Move-Folder -AdminSiteUrl $AdminSiteUrl -FolderSourceUrl $FolderSourceURL -FolderTargetUrl $FolderTargetURL
        }
    }
}

# End Timer
Write-Host "Total Time: $($elapsed.Elapsed.ToString())"

# Clear all variables except for Credentials
Get-Variable -Exclude $UserCredential | Remove-Variable * -ErrorAction SilentlyContinue

 

This Post Has 4 Comments

  1. Gavin

    Hi, receiving this error:
    Select SharePoint site collection type by typing its number: 1
    Get-SPOSite : No connection available. Use Connect-SPOService before running this CmdLet.
    At C:\scripts\move_SP.ps1:43 char:28
    + $SiteCollections = Get-SPOSite | Where-Object {($Exclusions – …
    + ~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-SPOSite], InvalidOperationException
    + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.Online.SharePoint.PowerShell.GetSite

    1. Pavel Bludov

      Hi Gavin,
      It looks like you are not connected to your SharePoint Admin site.
      Please make sure all links are correct for you at the top of the script and try to replace line#305 with this:
      Connect-PnPOnline -Url $AdminSiteUrl

  2. P

    Hey there,

    What kind of path is it looking for at ‘Provide the path of the folder:’ step? I’ve tried full URL, single folder name with no spaces, a folder name with quotes around it for folder name with spaces – none of them work and all result in ‘Cannot find the folder!’

    The folders reside in the default Documents library, so ‘Documents\Folder\Subfolder’ is the path I’m trying to use. Any ideas?

    Thanks!

    1. Paul Bludov

      Hello,
      Thanks for stopping by. That step uses get-pnpfolder, so the following example should help:
      get-pnpfolder -Url “https://contoso.sharepoint.com/sites/IT/Shared Documents/IT Infrastructure”
      If you copy a URL from the browser, then “Shared Documents” must be decoded from “Shared%20Documents”.
      As far as the rest of the folder names, they are put in as they appear in the UI.

Leave a Reply