How to copy list items with people and group columns between site collections using CSOM

Recently I had to work on an issue where a user needed to migrate a list from one site collection to another in a different site collection. He used CSOM for this but was challenged by the fact that the list also contained several people and group columns which cannot just be copied over to the new site collection, as the users will have different lookup ids in each site collection.

It took me a couple of minutes to assemble the necessary lines of code which I would like to share with you as well in case you have a need to do something similar.

The code below has been simplified and copies only one people and group column to describe the concept. For a real world scenario you might want to add code enumerate the columns to copy all columns in the list.

using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Principal;
using System.Security;
using Microsoft.SharePoint.Client;

namespace StefanG.Tools
{
    class CopyPeopleColumn
    {
        // helper method to lookup a user in the user info list
        static string LookupLoginNameInUserInfoList
                              (ClientContext context, int lookupId)
        {
            var username = string.Empty;

            var userInfoList = context.Web.SiteUserInfoList;
            context.Load(userInfoList);

            ListItem item = userInfoList.GetItemById(lookupId);
            context.Load(item);
            context.ExecuteQuery();

            loginName = item["Name"as string;
            return loginName;
        }

        static void Main(string[] args)
        {
            // add code to configure the credentials for SPO
            string userid = …;
            string pass = …;

            // create the SecureString object for the password
            SecureString password = new SecureString();
            foreach (char a in pass) { password.AppendChar(a); }

            // create the SPO credentials
            ICredentials spoCred = 
                new Microsoft.SharePoint.Client.SharePointOnlineCredentials(userid,password);

            // read people and groups field from source list

            // create a client context to the source site collection using the 
            // credentials created earlier
            ClientContext ctx = new ClientContext("https://url-to-source-site/");
            ctx.Credentials = spoCred;

            // get all the objects down to the list item we want to copy
            Web web = ctx.Web;
            ctx.Load(web);

            List list = web.Lists.GetByTitle("Source List");
            ctx.Load(list);

            // for demo purposes I assume an item with Id 1 exists
            ListItem item = list.GetItemById(1);   
            ctx.Load(item);

            ctx.ExecuteQuery();

            // read the user details from the people and group column
            FieldUserValue fuv = (FieldUserValue)item["user_column"];

            // use the lookup id to get the login name from the 
            // user information list of the source site collection
            string loginName = LookupLoginNameInUserInfoList(ctx, fuv.LookupId);

            // copy the content over to the new list

            // create a cli
ent context to the target site collection using the 

            // credentials created earlier
            ClientContext ctx2 = new ClientContext("https://url-to-target-site/");
            ctx2.Credentials = spoCred;

            // get all the objects down to the list we want to copy to
            Web web2 = ctx2.Web;
            ctx2.Load(web2);

            List list2 = web2.Lists.GetByTitle("Workload Technology Contacts");
            ctx2.Load(list2);
            ctx2.ExecuteQuery();

            // ensure that the user with the login name is populated into the 
            // user information list in the target site collection
            User newUser = web2.EnsureUser(loginName);
            ctx2.Load(newUser);
            ctx2.ExecuteQuery();

            // construct the value of the people or group column for the user
            FieldUserValue newValue = new FieldUserValue();
            newValue.LookupId = newUser.Id;

            // create a new list item and assign field value
            ListItem targetListItem = list2.AddItem(new ListItemCreationInformation());
            targetListItem["user_column"] = newValue;

            // write back to the target list
            targetListItem.Update();
            ctx2.ExecuteQuery();

        }
    }
}

7 Comments


  1. Very nice. Thank you, Stefan!

    Reply

  2. Recently I had to work on an issue where a user needed to migrate a list from one site collection to

    Reply

  3. Super article. Thank you very much. I actually was encountering this issue. THANK YOU VERY MUCH.

    Reply

  4. Como estrenamos mes nuevo (en plenos carnavales :P), toca un nuevo recopilatorio de enlaces interesantes

    Reply

  5. Thanks & Good Information Provide.

    Reply

  6. How about migrating legacy site collections with long-gone orphan users? Server-side PowerShell might suffice?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.