I recently had a requirement to move all the contents of a document library to another library and anybody that has had the displeasure of having to move files in SharePoint knows what a pain that can be.
To make matters worse, due to the specific setup I was dealing with the ‘Content & Structure’ tool was a non-option as it wasn’t functioning correctly and there were a large number of nested folders in the source library. Luckily this gave me the chance to use one of my favourite power tools – PowerShell.
This article contains a script which will copy all contents of a single library to another library, by using the built-in MoveTo command where possible so no data is lost or by copying if the source and target libraries are in different site collections.
PowerShell Script
Instructions
- This should be run on the SharePoint server, running it remotely will require modification.
- Running user should ideally have admin access, but full access to both libraries and the server should be adequate.
- Update the ‘Static Variables’ –
- SourceWebURL
- SourceLibraryTitle
- DestinationWebUrl
- DestinationLibraryTitle
Script
$ver = $host | select version if($Ver.version.major -gt 1) {$Host.Runspace.ThreadOptions = "ReuseThread"} if(!(Get-PSSnapin Microsoft.SharePoint.PowerShell -ea 0)) { Write-Progress -Activity "Loading Modules" -Status "Loading Microsoft.SharePoint.PowerShell" Add-PSSnapin Microsoft.SharePoint.PowerShell } $ErrorActionPreference = "Stop" #Set Static Variables $SourceWebURL = "https://sharepoint.domain/site" #The URL of the source website $SourceLibraryTitle = "libraryTitle" # The title of the source list $DestinationWebURL = "https://sharepoint.domain/site" #The URL of the destination website $DestinationLibraryTitle = "libraryTitle" #The title of the destination list ######################### Gather relevant details ################################################### #Retrieve the source web and list $sWeb = Get-SPWeb $SourceWebURL $sList = $sWeb.Lists | ? {$_.Title -eq $SourceLibraryTitle} if($sList -eq $null) { throw "Didn't find source list" } #Retrieve the destination web and list $dWeb = Get-SPWeb $DestinationWebURL $dList = $dWeb.Lists | ? {$_.title -like $DestinationLibraryTitle} if($dList -eq $null) { throw "Didn't find target list" } #Retrieve all folders in the source list. $AllFolders = $sList.Folders $allItems = $sList.Items # Check whether Check-In enabled on target library $checkinEnabled = $dList.ForceCheckout ################### Create all folders in new location ############################################## $sortedFolders = $AllFolders.Folder | sort $_.Url # Loop through the entire list of folders $progressCount = 0 foreach($Folder in $sortedFolders) { # Just writes a nice progress report Write-Progress -Id 0 -Activity "Creating folders in target directory" -Status "$progressCount of $($sortedFolders.Count)" -PercentComplete (($progressCount / $sortedFolders.Count) * 100) # Define the new location of the folder $parentUrl = $Folder.ParentFolder.Url -replace $sList.RootFolder.Name, $dList.RootFolder.Name $newLocation = $Folder.Url -replace $sList.RootFolder.Name, $dList.RootFolder.Name #If a matching folder isn't found in the new library then create it if(!($dList.Folders | ? {$_.URL -eq $newLocation})) { $newFolder = $dList.AddItem(($DestinationWebURL + "/" + $parentUrl), [Microsoft.SharePoint.SPFileSystemObjectType]::Folder, $Folder.Name) $newFolder["Title"] = $Folder.Name $newFolder.Update() } $progressCount++ } # Stops the progress report Write-Progress -Id 0 -Activity " " -Status " " -Completed #################### Move files if in same web ###################################################### # If in the same location then move the documents $progressCount = 0 if($SourceWebURL -eq $DestinatioNWebURL) { #Move all of the documents $count = $allItems.Count - 1 #Loop through each of the documents discovered in the root of the library and move any items found while($count -ne 0) { # Just writes a nice progress report Write-Progress -Id 0 -Activity "Moving documents to target directory" -Status "$progressCount of $($allItems.Count)" -PercentComplete (($progressCount / $allItems.Count) * 100) # Work out the new destination then move the file $itemNewUrl = $allItems[$count].Url -replace $sList.RootFolder.Name, $dList.RootFolder.Name $Dest = $DestinationWebURL + "/" + $itemNewUrl $allItems[$count].File.moveTo($Dest, $true) $count-- $progressCOunt++ } } # Stops the progress report Write-Progress -Id 0 -Activity " " -Status " " -Completed ###################### Copy files if different web ################################################# # If the source and destination are different sites then need to copy the item over $progressCount = 0 if($SourceWebURL -ne $DestinationWebURL) { #Loop through each of the documents discovered in the root of the library and perform some action foreach($Item in $AllItems) { # Just writes a nice progress report Write-Progress -Id 0 -Activity "Copyring documents to target directory" -Status "$progressCount of $($AllItems.Count)" -PercentComplete (($progressCount / $AllItems.Count) * 100) #Get the Binary Stream of the referenced file, such that we can create the same file in the destination environment $sBytes = $Item.File.OpenBinary() #Create A New file using the name and binary stream from the original document, assign it to a variable. This variable will later be called when setting properties $dFile = $dList.RootFolder.Files.Add($Item.Name, $sBytes, $true) #Return all fields for the source item which are not read-only $AllFields = $Item.Item.Fields | ? {!($_.sealed)} #Loop through all of the fields returned and perform some action foreach($Field in $AllFields) { #If the source item has a property that matches the name of the field perform some action if($Item.Properties[$Field.Title]) { #If the destination file does not contain the same property as the source item perform some action. if(!($dFile.Properties[$Field.title])) { #Add a property to the file matching title and value of the same field in the original item $dFile.AddProperty($Field.Title, $Item.Properties[$Field.Title]) } else { #If the property already exists, set the value on the destination item to the same value as it was in the source item. $dFile.Properties[$Field.Title] = $Item.Properties[$Field.Title] } } } #Commit the changes by updating the destination file. $dFile.Update() if($checkinEnabled -and $item.File.CheckOutStatus -ne "None") { $item.File.CheckIn("Checked In after scripts Copy/Move") } } } # Stops the progress report Write-Progress -Id 0 -Activity " " -Status " " -Completed
I would like to thank Roger Cormier for his article ‘How to Copy SharePoint Documents Between Site Collections Using PowerShell‘ which provided a good basis for this script.
Hello, can we move a page located on the root to a site library with this script ? Thanks
LikeLike
To move all files it has to be changed to “while($count -ne -1)”.
LikeLike