Question

I am trying to copy the Files and Folders with meta data from one library to another library,in SharePoint Online using powershell CSOM, i am getting this error

"Exception calling "ExecuteQuery" with "0" argument(s): "The operation has timed out."" It works more than half the time, but will often give me this error upon calling the ExecuteQuery() command:

this is my code

#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
{
  param
    (
        [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
        $SourceFolder.Context.Load($SourceFilesColl)
        $SourceFolder.Context.ExecuteQuery()

        #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
            $SourceFolder.Context.Load($SourceListItem)
            $SourceFolder.Context.ExecuteQuery()

            #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"]
            $TargetListItem.Update()
            $TargetFolder.Context.ExecuteQuery()

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

        #Process Sub Folders
        $SubFolders = $SourceFolder.Folders
        $SourceFolder.Context.Load($SubFolders)
        $SourceFolder.Context.ExecuteQuery()
        Foreach($SubFolder in $SubFolders)
        {
            If($SubFolder.Name -ne "Forms")
            {
                #Prepare Target Folder
                $TargetFolderURL = $SubFolder.ServerRelativeUrl -replace $SourceLibrary.RootFolder.ServerRelativeUrl, $TargetLibrary.RootFolder.ServerRelativeUrl
                Try {
                        $Folder=$TargetFolder.Context.web.GetFolderByServerRelativeUrl($TargetFolderURL)
                        $TargetFolder.Context.load($Folder)
                        $TargetFolder.Context.ExecuteQuery()
                    }
                catch {
                        #Create Folder
                        if(!$Folder.Exists)
                        {
                            $TargetFolderURL
                            $Folder=$TargetFolder.Context.web.Folders.Add($TargetFolderURL)
                            $TargetFolder.Context.Load($Folder)
                            $TargetFolder.Context.ExecuteQuery()
                            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

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

$TargetLibrary = $TargetCtx.Web.Lists.GetByTitle($TargetLibraryName)
$TargetCtx.Load($TargetLibrary)
$TargetCtx.Load($TargetLibrary.RootFolder)
$TargetCtx.ExecuteQuery()

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


Could anyone please help me?

Was it helpful?

Solution

Since it is working sometimes, it is likely just a timeout and nothing code related. That means the query is taking too long to execute. Probably due to the amount of items in some lists. There are multiple answers on this. I'd imagine increasing the timeout or not using execute query as suggested in them would do it.

Operation has timed out using powershell script https://stackoverflow.com/questions/45343993/powershell-sharepoint-online-executequery-error-timed-out

OTHER TIPS

This exception is not because of your script but it due to the process takes long time and it gets timed out. you can resolve it by setting the RequestTimeOut property of Context to milliseconds like:

$context.RequestTimeOut = 5000*10000

Reference: Operation has timed out using powershell script

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top