I'm copying the files between site collection document libraries in share point online using the below script but it failing to copy the files when the author of the files no longer exists. Below is my code. Could any one help on how to map an invalid user with exciting active user while copying?

#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"

Function Copy-AllFilesWithMetadata
        [Parameter(Mandatory=$true)] [Microsoft.SharePoint.Client.Folder] $SourceFolder,
        [Parameter(Mandatory=$true)] [Microsoft.SharePoint.Client.Folder] $TargetFolder
    Try {
        #Get all Files from the source folder
        $SourceFilesColl = $SourceFolder.Files

        #Iterate through each file and copy
        Foreach($SourceFile in $SourceFilesColl)
            #Get the source file
            $FileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($SourceFolder.Context, $SourceFile.ServerRelativeUrl)

            #Copy File to the Target location
            $TargetFileURL = $TargetFolder.ServerRelativeUrl+"/"+$SourceFile.Name
            [Microsoft.SharePoint.Client.File]::SaveBinaryDirect($TargetFolder.Context, $TargetFileURL, $FileInfo.Stream,$True)

            #Copy Metadata field values
            $SourceListItem = $SourceFile.ListItemAllFields

            #Get the new file created
            $TargetFile = $TargetFolder.Context.Web.GetFileByServerRelativeUrl($TargetFileURL)
            $TargetListItem = $TargetFile.ListItemAllFields

            #Set Metadata values from the source
            $Author =$TargetFolder.Context.web.EnsureUser($SourceListItem["Author"].Email)
            $TargetListItem["Author"] = $Author
            $Editor =$TargetFolder.Context.web.EnsureUser($SourceListItem["Editor"].Email)
            $TargetListItem["Editor"] = $Editor
            $TargetListItem["Created"] = $SourceListItem["Created"]
            $TargetListItem["Modified"] = $SourceListItem["Modified"]

            Write-host -f Green "Copied File '$($SourceFile.ServerRelativeUrl)' to '$TargetFileURL'"

        #Process Sub Folders
        $SubFolders = $SourceFolder.Folders
        Foreach($SubFolder in $SubFolders)
            If($SubFolder.Name -ne "Forms")
                #Prepare Target Folder
                $TargetFolderURL = $SubFolder.ServerRelativeUrl -replace $SourceLibrary.RootFolder.ServerRelativeUrl, $TargetLibrary.RootFolder.ServerRelativeUrl
                Try {
                catch {
                        #Create Folder
                            Write-host "Folder Added:"$SubFolder.Name -f Yellow
                #Call the function recursively
                Copy-AllFilesWithMetadata -SourceFolder $SubFolder -TargetFolder $Folder
    Catch {
        write-host -f Red "Error Copying File!" $_.Exception.Message

#Set Parameter values
$SourceSiteURL= Read-Host -Prompt 'Enter Source Site URL'
$TargetSiteURL= Read-Host -Prompt 'Enter Target Site URL'

$SourceLibraryName= Read-Host -Prompt 'Enter Source Library Name'
$TargetLibraryName= Read-Host -Prompt 'Enter Target Library Name'

#Setup Credentials to connect
$Cred= Get-Credential
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)

#Setup the contexts
$SourceCtx = New-Object Microsoft.SharePoint.Client.ClientContext($SourceSiteURL)
$SourceCtx.Credentials = $Credentials
$TargetCtx = New-Object Microsoft.SharePoint.Client.ClientContext($TargetSiteURL)
$TargetCtx.Credentials = $Credentials

$SourceCtx.RequestTimeOut = 5000*10000
$TargetCtx.RequestTimeOut = 5000*10000

#Get the source library and Target Libraries
$SourceLibrary = $SourceCtx.Web.Lists.GetByTitle($SourceLibraryName)

$TargetLibrary = $TargetCtx.Web.Lists.GetByTitle($TargetLibraryName)

#Call the function
Copy-AllFilesWithMetadata -SourceFolder $SourceLibrary.RootFolder -TargetFolder $TargetLibrary.RootFolder


Try to run below PowerShell as administrator.

$SiteURL = "your site collection URL"
$SourceFolderURL = "/sites/site collection name/document library name"
$TargetFolderURL = "/sites/site collection name/document library name"

#Connect to PnP Online
Connect-PnPOnline -Url $SiteURL -UseWebLogin

#Copy All Files and Folders between source and target folders
Copy-PnPFile -SourceUrl $SourceFolderURL -TargetUrl $TargetFolderURL -SkipSourceFolderName -Force -OverwriteIfAlreadyExists
  • Emily Du - Thanks for your response. My source library in one site collection and destination library in another site collection. Could you please help on this? – taruki_MS May 22 '20 at 5:02
  • I tried this and worked between site collections thanks a lot. Is there a way to copy the files including metadata? – taruki_MS May 22 '20 at 7:30
  • You could archive this through save the library as a template. Here‘re some references: sharepointdiary.com/2017/08/… support.microsoft.com/en-us/office/… – Emily Du - MSFT May 22 '20 at 9:41
  • Thanks for an update.. but save list as template won't work when library has more data in side – taruki_MS May 22 '20 at 10:02
  • I am getting the below error when copying files from source to destination library after some time. Error: Copy-PnPFile : The underlying connection was closed: An unexpected error occurred on a receive. Added the below line to top of my script but still receiving that error. [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; any help on this? – taruki_MS Sep 14 '20 at 15:47

Use PnP PowerShell to copy all files and folders between document libraries with metadata.

#Function to copy all Items from one library to another
Function Copy-AllDocuments($SourceLibraryName, $TargetLibraryName)
#Get Source and Target Libraries
$SourceLibrary = Get-PnPList -Identity $SourceLibraryName -Includes RootFolder
$TargetLibrary = Get-PnPList -Identity $TargetLibraryName -Includes RootFolder

#Copy All Files and Folders from Source to Target Library
Copy-PnPFile -SourceUrl $SourceLibrary.RootFolder.ServerRelativeUrl -TargetUrl 
$TargetLibrary.RootFolder.ServerRelativeUrl -OverwriteIfAlreadyExists -Force - 

#Get All Items from Source Library
$SourceItems = Get-PnPListItem -List $SourceLibraryName
$TargetItems = Get-PnPListItem -List $TargetLibraryName

#Get All Items in the Source Library
ForEach($SourceItem in $SourceItems)
    #Get Metadata from Source Items
    $Metadata = @{
        'Title' = $SourceItem.FieldValues.Title
        'Created'= $SourceItem.FieldValues.Created.DateTime
        'Modified' = $SourceItem.FieldValues.Modified.DateTime
        'Author' = $SourceItem.FieldValues.Author.Email
        'Editor' = $SourceItem.FieldValues.Editor.Email
    #Update Metadata in Target Items
    ForEach($TargetItem in $TargetItems)
        If($SourceItem.FieldValues.FileLeafRef -eq 
            Set-PnPListItem -List $TargetLibrary -Identity $TargetItem.Id -Values $Metadata | Out-Null

#Connect to PnP Online
$SiteURL = "your site collection URL"
Connect-PnPOnline -Url $SiteURL -Credentials (Get-Credential)

#Call the function to copy all files between document libraries
Copy-AllDocuments "document library A name" "document library B name"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.