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.
  1. $credentials = Get-Credential
  2. $filename = 'D:\Arvind\safe\secretfile.txt'
  3. $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.
  1. #Set Parameters
  2. $todayDate = (Get-Date).toString("yyyy_MM_dd")
  3. $Logfile = "D:\Logs\copyListItems_"+$todayDate+".txt"
  4. $srcListSiteUrl = "Source Site Url"
  5. $SourceListName = "SourceListName"
  6. $dstListSiteUrl = "Destination Site Url"
  7. $TargetListName = "DestinationListName"
  8. $sourceQuery = "Your Query"
5) Complete the Powershell Script
  1. #Set Global Variable
  2. $global:spoUsers = @{};
  3. #Load SharePoint CSOM Assemblies
  4. Add-Type -path 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll'
  5. Add-Type -path 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll'
  6. Function LogWrite
  7. {
  8. Param ([string]$logstring)
  9. Add-content $Logfile -value $logstring
  10. }
  11. Function Ensure-SPOUser()
  12. {
  13. Param(
  14. [Parameter(Mandatory=$true)] [string]$emailID,
  15. [Parameter(Mandatory=$true)] [Microsoft.SharePoint.Client.ClientContext]$Ctx
  16. )
  17. Try {
  18. #ensure sharepoint online user
  19. Write-Host "Verify User" $emailID
  20. LogWrite "Verify User" $emailID
  21. $Web = $Ctx.Web
  22. $User=$Web.EnsureUser($emailID)
  23. $global:spoUsers.Add($emailID , $User)
  24. return $User
  25. }
  26. Catch {
  27. #write-host -f Red "Error:" $_.Exception.Message
  28. return $null
  29. }
  30. }
  31. Function UpdateSystemCol()
  32. {
  33. Param(
  34. [Parameter(Mandatory=$true)] $SourceItem,
  35. [Parameter(Mandatory=$true)] $ListItem,
  36. [Parameter(Mandatory=$true)] $destCtx
  37. )
  38. $authorUser = ""
  39. $editorUser = ""
  40. if(!([string]::IsNullOrEmpty($SourceItem["Author"].Email)))
  41. {
  42. #check user present in hashtable
  43. if($global:spoUsers.ContainsKey($SourceItem["Author"].Email))
  44. {
  45. $ListItem["Author"] = $global:spoUsers[$SourceItem["Author"].Email]
  46. } else
  47. {
  48. $authorUser = Ensure-SPOUser $SourceItem["Author"].Email $destCtx
  49. $ListItem["Author"] = $authorUser
  50. }
  51. }
  52. elseif(([string]::IsNullOrEmpty($SourceItem["Author"].Email)) -or $authorUser -eq $null)
  53. {
  54. $ListItem["Author"] = $currentUser
  55. }
  56. if(!([string]::IsNullOrEmpty($SourceItem["Editor"].Email)))
  57. {
  58. #check user present in hashtable
  59. if($global:spoUsers.ContainsKey($SourceItem["Editor"].Email))
  60. {
  61. $ListItem["Editor"] = $global:spoUsers[$SourceItem["Editor"].Email]
  62. } else
  63. {
  64. $editorUser = Ensure-SPOUser $SourceItem["Editor"].Email $destCtx
  65. $ListItem["Editor"] = $editorUser
  66. }
  67. }
  68. elseif(([string]::IsNullOrEmpty($SourceItem["Editor"].Email)) -or $editorUser -eq $null)
  69. {
  70. $ListItem["Editor"] = $currentUser
  71. }
  72. $ListItem["Created"] = $SourceItem["Created"]
  73. $ListItem["Modified"] = $SourceItem["Modified"]
  74. return $ListItem
  75. }
  76. Function Copy-ListItems()
  77. {
  78. param
  79. (
  80. [Parameter(Mandatory=$true)] [string] $siteURL,
  81. [Parameter(Mandatory=$true)] [string] $destSiteURL,
  82. [Parameter(Mandatory=$true)] [string] $SourceListName,
  83. [Parameter(Mandatory=$true)] [string] $TargetListName,
  84. [Parameter(Mandatory=$true)] [string] $query,
  85. [Parameter(Mandatory=$true)] [string] $Logfile
  86. )
  87. Try {
  88. If(!(test-path $Logfile))
  89. {
  90. New-Item -Path $Logfile -Type File -Force | Out-Null
  91. }
  92. LogWrite "Copy-ListItems Fuction Called"
  93. #Passing Credentials
  94. $credPath = 'D:\Arvind\safe\secretfile.txt'
  95. $fileCred = Import-Clixml -path $credpath
  96. $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($fileCred.UserName, $fileCred.Password)
  97. #Setup the source context
  98. $sourceCtx = New-Object Microsoft.SharePoint.Client.ClientContext($siteURL)
  99. $sourceCtx.Credentials = $Cred
  100. #Setup the destination Context
  101. $destCtx = New-Object Microsoft.SharePoint.Client.ClientContext($destSiteURL)
  102. $destCtx.Credentials = $Cred
  103. LogWrite "User Credential is valid and It is Successfully Login"
  104. #Get Current loged User on destination Site
  105. $currentUser =$destCtx.Web.CurrentUser;
  106. $destCtx.Load($currentUser)
  107. $destCtx.ExecuteQuery()
  108. $currentUser= $destCtx.Web.EnsureUser($currentUser.Email)
  109. $destCtx.Load($currentUser)
  110. $destCtx.ExecuteQuery()
  111. #Get the Source List and Target Lists
  112. $SourceList = $sourceCtx.Web.Lists.GetByTitle($SourceListName)
  113. $TargetList = $destCtx.Web.Lists.GetByTitle($TargetListName)
  114. #Get CAML Query object
  115. $camlquery = New-Object Microsoft.SharePoint.Client.CamlQuery;
  116. $camlquery.ViewXml= $query
  117. LogWrite "Query:" $query
  118. #Get All Items from the Source List in batches
  119. Write-Progress -Activity "Reading Source..." -Status "Getting Items from Source List. Please wait..."
  120. $SourceListItems = $SourceList.GetItems($camlquery)
  121. $sourceCtx.Load($SourceListItems)
  122. $sourceCtx.ExecuteQuery()
  123. $SourceListItemsCount= $SourceListItems.count
  124. Write-host "Total Number of Items Found:"$SourceListItemsCount -foregroundcolor black -backgroundcolor Green
  125. LogWrite "Total Number of Items Found:"$SourceListItemsCount
  126. #Get All fields from Source List & Target List
  127. $SourceListFields = $SourceList.Fields
  128. $sourceCtx.Load($SourceListFields)
  129. $TargetListFields = $TargetList.Fields
  130. $destCtx.Load($TargetListFields)
  131. $sourceCtx.ExecuteQuery()
  132. $destCtx.ExecuteQuery()
  133. #Loop through each item in the source and Get column values, add them to target
  134. [int]$Counter = 1
  135. #Get each column value from source list and add them to target
  136. ForEach($SourceItem in $SourceListItems)
  137. {
  138. $versionColl = $SourceItem.Versions
  139. $sourceCtx.Load($versionColl)
  140. $sourceCtx.ExecuteQuery()
  141. Write-Host "ID: "$SourceItem.ID "Version Count: " $versionColl.Count
  142. LogWrite "ID: "$SourceItem.ID "Version Count: " $versionColl.Count
  143. $NewItem =New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
  144. $ListItem = $TargetList.AddItem($NewItem)
  145. #check the number of version available. If version is greater than 1.0 then create item by iterating the for loop with descending order.
  146. Write-Progress -Activity "Copying List Items:" -Status "Copying Item ID '$($SourceItem.Id)' from Source List ($($Counter) of $($SourceListItemsCount))" -PercentComplete (($Counter / $SourceListItemsCount) * 100)
  147. #check the number of version.
  148. if($versionColl.Count -gt 1)
  149. {
  150. for($i= $versionColl.Count-1; $i -ge 0; $i--)
  151. {
  152. $version = $versionColl[$i];
  153. Foreach($SourceField in $SourceListFields)
  154. {
  155. #Skip Read only, hidden fields, content type and attachments
  156. If((-Not ($SourceField.ReadOnlyField)) -and (-Not ($SourceField.Hidden)) -and ($SourceField.InternalName -ne "ContentType") -and ($SourceField.InternalName -ne "Attachments") )
  157. {
  158. $TargetField = $TargetListFields | where { $_.Internalname -eq $SourceField.Internalname}
  159. if($TargetField -ne $null -and $SourceField.InternalName -ne "Author" -and $SourceField.InternalName -ne "Editor" -and $SourceField.InternalName -ne "Created" -and $SourceField.InternalName -ne "Modified")
  160. {
  161. $ListItem[$TargetField.InternalName] =$version[$SourceField.InternalName]
  162. }
  163. }
  164. }
  165. if($i -eq $versionColl.Count-1)
  166. {
  167. $ListItem =UpdateSystemCol $SourceItem $ListItem $destCtx
  168. }
  169. else
  170. {
  171. $authorUser = ""
  172. $editorUser = ""
  173. if(!([string]::IsNullOrEmpty($SourceItem["Editor"].Email)))
  174. {
  175. #check user present in hashtable
  176. if($global:spoUsers.ContainsKey($SourceItem["Editor"].Email))
  177. {
  178. $ListItem["Editor"] = $global:spoUsers[$SourceItem["Editor"].Email]
  179. }
  180. else
  181. {
  182. $editorUser = Ensure-SPOUser $SourceItem["Editor"].Email $destCtx
  183. $ListItem["Editor"] = $editorUser
  184. }
  185. }
  186. elseif(([string]::IsNullOrEmpty($SourceItem["Editor"].Email)) -or $editorUser -eq $null)
  187. {
  188. $ListItem["Editor"] = $currentUser
  189. }
  190. $ListItem["Created"] = $SourceItem["Created"]
  191. $ListItem["Modified"] = $SourceItem["Modified"]
  192. }
  193. $ListItem.Update()
  194. $destCtx.ExecuteQuery()
  195. }
  196. }
  197. else #If only one version available
  198. {
  199. $version = $versionColl[0];
  200. Foreach($SourceField in $SourceListFields)
  201. {
  202. #Skip Read only, hidden fields, content type and attachments
  203. If((-Not ($SourceField.ReadOnlyField)) -and (-Not ($SourceField.Hidden)) -and ($SourceField.InternalName -ne "ContentType") -and ($SourceField.InternalName -ne "Attachments") )
  204. {
  205. $TargetField = $TargetListFields | where { $_.Internalname -eq $SourceField.Internalname}
  206. if($TargetField -ne $null -and $SourceField.InternalName -ne "Author" -and $SourceField.InternalName -ne "Editor" -and $SourceField.InternalName -ne "Created" -and $SourceField.InternalName -ne "Modified")
  207. {
  208. $ListItem[$TargetField.InternalName] =$version[$SourceField.InternalName]
  209. }
  210. }
  211. }
  212. $ListItem = UpdateSystemCol $SourceItem $ListItem $destCtx
  213. $ListItem.Update()
  214. $destCtx.ExecuteQuery()
  215. }
  216. Write-Host "Copied Item ID from Source to Target List:$($SourceItem.Id) ($($Counter) of $($SourceListItemsCount))"
  217. $Counter++
  218. }
  219. write-host -f Green "Total List Items Copied from '$SourceListName' to '$TargetListName' : $($SourceListItems.count)"
  220. LogWrite "Total List Items Copied from '$SourceListName' to '$TargetListName' : $($SourceListItems.count)"
  221. }
  222. Catch {
  223. write-host -f Red "Error Copying List Items!" $_.Exception.Message
  224. LogWrite "Error Copying List Items!" $_.Exception.Message
  225. }
  226. }
  227. #Set Parameters
  228. $todayDate = (Get-Date).toString("yyyy_MM_dd")
  229. $Logfile = "D:\Logs\copyListItems_"+$todayDate+".txt"
  230. $srcListSiteUrl = "SourceSite Url"
  231. $SourceListName = "SourceList Name"
  232. $dstListSiteUrl = "Destination Site"
  233. $TargetListName = "DestinationList Name"
  234. $sourceQuery = "Your Query"
  235. #Passing Credentials
  236. $credPath = 'D:\Arvind\safe\secretfile.txt'
  237. $fileCred = Import-Clixml -path $credpath
  238. #Call the function to copy list items
  239. Copy-ListItems -siteURL $srcListSiteUrl -destSiteURL $dstListSiteUrl -SourceListName $SourceListName -TargetListName $TargetListName -query $sourceQuery -logFile $Logfile