Introduction
1) Download and Install SharePoint Online SDK
here.
2) Pass credentials to SharePoint Online using an external file. There are different ways too, referred to on this
site.
- $credentials = Get-Credential
- $filename = 'D:\Arvind\safe\secretfile.txt'
- $credentials | Export-Clixml -path $filename
3) Make sure that SourceList Column and DestinationList column are the same.
4) Now pass the parameter to the script.
- #Set Parameters
- $todayDate = (Get-Date).toString("yyyy_MM_dd")
- $Logfile = "D:\Logs\copyListItems_"+$todayDate+".txt"
- $srcListSiteUrl = "Source Site Url"
- $SourceListName = "SourceListName"
- $dstListSiteUrl = "Destination Site Url"
- $TargetListName = "DestinationListName"
- $sourceQuery = "Your Query"
5) Complete the Powershell Script
- #Set Global Variable
- $global:spoUsers = @{};
-
- #Load SharePoint CSOM Assemblies
- Add-Type -path 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll'
- Add-Type -path 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll'
-
- Function LogWrite
- {
- Param ([string]$logstring)
-
- Add-content $Logfile -value $logstring
- }
- Function Ensure-SPOUser()
- {
- Param(
- [Parameter(Mandatory=$true)] [string]$emailID,
- [Parameter(Mandatory=$true)] [Microsoft.SharePoint.Client.ClientContext]$Ctx
- )
- Try {
- #ensure sharepoint online user
- Write-Host "Verify User" $emailID
- LogWrite "Verify User" $emailID
- $Web = $Ctx.Web
- $User=$Web.EnsureUser($emailID)
- $global:spoUsers.Add($emailID , $User)
- return $User
- }
- Catch {
- #write-host -f Red "Error:" $_.Exception.Message
- return $null
- }
- }
-
- Function UpdateSystemCol()
- {
- Param(
- [Parameter(Mandatory=$true)] $SourceItem,
- [Parameter(Mandatory=$true)] $ListItem,
- [Parameter(Mandatory=$true)] $destCtx
- )
- $authorUser = ""
- $editorUser = ""
- if(!([string]::IsNullOrEmpty($SourceItem["Author"].Email)))
- {
- #check user present in hashtable
- if($global:spoUsers.ContainsKey($SourceItem["Author"].Email))
- {
- $ListItem["Author"] = $global:spoUsers[$SourceItem["Author"].Email]
- } else
- {
- $authorUser = Ensure-SPOUser $SourceItem["Author"].Email $destCtx
- $ListItem["Author"] = $authorUser
- }
- }
- elseif(([string]::IsNullOrEmpty($SourceItem["Author"].Email)) -or $authorUser -eq $null)
- {
- $ListItem["Author"] = $currentUser
- }
- if(!([string]::IsNullOrEmpty($SourceItem["Editor"].Email)))
- {
- #check user present in hashtable
- if($global:spoUsers.ContainsKey($SourceItem["Editor"].Email))
- {
- $ListItem["Editor"] = $global:spoUsers[$SourceItem["Editor"].Email]
- } else
- {
- $editorUser = Ensure-SPOUser $SourceItem["Editor"].Email $destCtx
- $ListItem["Editor"] = $editorUser
- }
- }
- elseif(([string]::IsNullOrEmpty($SourceItem["Editor"].Email)) -or $editorUser -eq $null)
- {
- $ListItem["Editor"] = $currentUser
- }
- $ListItem["Created"] = $SourceItem["Created"]
- $ListItem["Modified"] = $SourceItem["Modified"]
- return $ListItem
- }
- Function Copy-ListItems()
- {
- param
- (
- [Parameter(Mandatory=$true)] [string] $siteURL,
- [Parameter(Mandatory=$true)] [string] $destSiteURL,
- [Parameter(Mandatory=$true)] [string] $SourceListName,
- [Parameter(Mandatory=$true)] [string] $TargetListName,
- [Parameter(Mandatory=$true)] [string] $query,
- [Parameter(Mandatory=$true)] [string] $Logfile
- )
- Try {
- If(!(test-path $Logfile))
- {
- New-Item -Path $Logfile -Type File -Force | Out-Null
- }
- LogWrite "Copy-ListItems Fuction Called"
- #Passing Credentials
- $credPath = 'D:\Arvind\safe\secretfile.txt'
- $fileCred = Import-Clixml -path $credpath
- $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($fileCred.UserName, $fileCred.Password)
-
- #Setup the source context
- $sourceCtx = New-Object Microsoft.SharePoint.Client.ClientContext($siteURL)
- $sourceCtx.Credentials = $Cred
-
- #Setup the destination Context
- $destCtx = New-Object Microsoft.SharePoint.Client.ClientContext($destSiteURL)
- $destCtx.Credentials = $Cred
- LogWrite "User Credential is valid and It is Successfully Login"
-
- #Get Current loged User on destination Site
- $currentUser =$destCtx.Web.CurrentUser;
- $destCtx.Load($currentUser)
- $destCtx.ExecuteQuery()
-
- $currentUser= $destCtx.Web.EnsureUser($currentUser.Email)
- $destCtx.Load($currentUser)
- $destCtx.ExecuteQuery()
-
- #Get the Source List and Target Lists
- $SourceList = $sourceCtx.Web.Lists.GetByTitle($SourceListName)
- $TargetList = $destCtx.Web.Lists.GetByTitle($TargetListName)
-
- #Get CAML Query object
- $camlquery = New-Object Microsoft.SharePoint.Client.CamlQuery;
- $camlquery.ViewXml= $query
- LogWrite "Query:" $query
-
- #Get All Items from the Source List in batches
- Write-Progress -Activity "Reading Source..." -Status "Getting Items from Source List. Please wait..."
- $SourceListItems = $SourceList.GetItems($camlquery)
- $sourceCtx.Load($SourceListItems)
- $sourceCtx.ExecuteQuery()
- $SourceListItemsCount= $SourceListItems.count
- Write-host "Total Number of Items Found:"$SourceListItemsCount -foregroundcolor black -backgroundcolor Green
- LogWrite "Total Number of Items Found:"$SourceListItemsCount
- #Get All fields from Source List & Target List
- $SourceListFields = $SourceList.Fields
- $sourceCtx.Load($SourceListFields)
-
- $TargetListFields = $TargetList.Fields
- $destCtx.Load($TargetListFields)
-
- $sourceCtx.ExecuteQuery()
- $destCtx.ExecuteQuery()
-
- #Loop through each item in the source and Get column values, add them to target
- [int]$Counter = 1
-
- #Get each column value from source list and add them to target
- ForEach($SourceItem in $SourceListItems)
- {
- $versionColl = $SourceItem.Versions
- $sourceCtx.Load($versionColl)
- $sourceCtx.ExecuteQuery()
- Write-Host "ID: "$SourceItem.ID "Version Count: " $versionColl.Count
- LogWrite "ID: "$SourceItem.ID "Version Count: " $versionColl.Count
- $NewItem =New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
- $ListItem = $TargetList.AddItem($NewItem)
-
- #check the number of version available. If version is greater than 1.0 then create item by iterating the for loop with descending order.
- Write-Progress -Activity "Copying List Items:" -Status "Copying Item ID '$($SourceItem.Id)' from Source List ($($Counter) of $($SourceListItemsCount))" -PercentComplete (($Counter / $SourceListItemsCount) * 100)
-
- #check the number of version.
- if($versionColl.Count -gt 1)
- {
- for($i= $versionColl.Count-1; $i -ge 0; $i--)
- {
- $version = $versionColl[$i];
- Foreach($SourceField in $SourceListFields)
- {
- #Skip Read only, hidden fields, content type and attachments
- If((-Not ($SourceField.ReadOnlyField)) -and (-Not ($SourceField.Hidden)) -and ($SourceField.InternalName -ne "ContentType") -and ($SourceField.InternalName -ne "Attachments") )
- {
- $TargetField = $TargetListFields | where { $_.Internalname -eq $SourceField.Internalname}
- if($TargetField -ne $null -and $SourceField.InternalName -ne "Author" -and $SourceField.InternalName -ne "Editor" -and $SourceField.InternalName -ne "Created" -and $SourceField.InternalName -ne "Modified")
- {
- $ListItem[$TargetField.InternalName] =$version[$SourceField.InternalName]
-
- }
- }
- }
- if($i -eq $versionColl.Count-1)
- {
- $ListItem =UpdateSystemCol $SourceItem $ListItem $destCtx
- }
- else
- {
- $authorUser = ""
- $editorUser = ""
- if(!([string]::IsNullOrEmpty($SourceItem["Editor"].Email)))
- {
- #check user present in hashtable
- if($global:spoUsers.ContainsKey($SourceItem["Editor"].Email))
- {
- $ListItem["Editor"] = $global:spoUsers[$SourceItem["Editor"].Email]
- }
- else
- {
- $editorUser = Ensure-SPOUser $SourceItem["Editor"].Email $destCtx
- $ListItem["Editor"] = $editorUser
- }
- }
- elseif(([string]::IsNullOrEmpty($SourceItem["Editor"].Email)) -or $editorUser -eq $null)
- {
- $ListItem["Editor"] = $currentUser
- }
-
- $ListItem["Created"] = $SourceItem["Created"]
- $ListItem["Modified"] = $SourceItem["Modified"]
- }
- $ListItem.Update()
- $destCtx.ExecuteQuery()
- }
- }
- else #If only one version available
- {
- $version = $versionColl[0];
- Foreach($SourceField in $SourceListFields)
- {
- #Skip Read only, hidden fields, content type and attachments
- If((-Not ($SourceField.ReadOnlyField)) -and (-Not ($SourceField.Hidden)) -and ($SourceField.InternalName -ne "ContentType") -and ($SourceField.InternalName -ne "Attachments") )
- {
- $TargetField = $TargetListFields | where { $_.Internalname -eq $SourceField.Internalname}
- if($TargetField -ne $null -and $SourceField.InternalName -ne "Author" -and $SourceField.InternalName -ne "Editor" -and $SourceField.InternalName -ne "Created" -and $SourceField.InternalName -ne "Modified")
- {
- $ListItem[$TargetField.InternalName] =$version[$SourceField.InternalName]
- }
- }
- }
- $ListItem = UpdateSystemCol $SourceItem $ListItem $destCtx
- $ListItem.Update()
- $destCtx.ExecuteQuery()
- }
- Write-Host "Copied Item ID from Source to Target List:$($SourceItem.Id) ($($Counter) of $($SourceListItemsCount))"
- $Counter++
- }
- write-host -f Green "Total List Items Copied from '$SourceListName' to '$TargetListName' : $($SourceListItems.count)"
- LogWrite "Total List Items Copied from '$SourceListName' to '$TargetListName' : $($SourceListItems.count)"
- }
- Catch {
- write-host -f Red "Error Copying List Items!" $_.Exception.Message
- LogWrite "Error Copying List Items!" $_.Exception.Message
- }
- }
-
- #Set Parameters
- $todayDate = (Get-Date).toString("yyyy_MM_dd")
- $Logfile = "D:\Logs\copyListItems_"+$todayDate+".txt"
-
- $srcListSiteUrl = "SourceSite Url"
- $SourceListName = "SourceList Name"
- $dstListSiteUrl = "Destination Site"
- $TargetListName = "DestinationList Name"
- $sourceQuery = "Your Query"
- #Passing Credentials
- $credPath = 'D:\Arvind\safe\secretfile.txt'
- $fileCred = Import-Clixml -path $credpath
- #Call the function to copy list items
- Copy-ListItems -siteURL $srcListSiteUrl -destSiteURL $dstListSiteUrl -SourceListName $SourceListName -TargetListName $TargetListName -query $sourceQuery -logFile $Logfile