Skip to main content

PowerShell Automation for Smart SharePoint List Migration

PowerShell Automation for Smart SharePoint List Migration

Migrating data between SharePoint environments is one of those tasks that looks simple on paper—but in practice, it’s easy to get tangled in duplicates, mismatched fields, or incomplete moves. With many organizations moving from on-premises SharePoint Server to SharePoint Online, automation becomes key to a smooth transition.

This guide walks through a PowerShell script that not only moves list items from an on-premises SharePoint list to the cloud but also checks for duplicates before copying. Let’s break it down.

Why Automate the Migration?

Traditional migrations often copy everything from the source list to the destination list—whether or not those items already exist in the target. The result? Duplicates, clutter, and a messy data clean-up later.

This script was designed to solve that. It brings intelligence into the migration process by checking for duplicates first, then deciding whether to move or just delete the source item. The decision is based on four fields that uniquely identify a record:

  • First Name
  • Last Name
  • Email
  • Phone Number

What the Script Does

Here’s a simple explanation of the workflow:

  1. Connects to the source SharePoint on-premises site and retrieves all list items.
  2. Connects to the destination SharePoint Online site using secure App-only authentication.
  3. For each item in the source:
    • Checks if an item with the same name, email, and phone already exists in the destination list.
    • If it exists → deletes the source item (no need to copy).
    • If it doesn’t exist → copies it to the destination and then deletes the source record.
  4. Displays progress messages along the way for visibility.

This approach ensures you migrate only unique items while keeping your lists synchronized and clean.

The Tools Involved

  • PowerShell — the engine driving the automation.
  • SharePoint Server Object Model (Get-SPWeb) — used for accessing items from on-premises SharePoint.
  • PnP PowerShell — used for connecting to SharePoint Online and adding list items.

Together, they bridge your on-premises and cloud environments with minimal manual effort.

Example PowerShell Script (with Dummy Values)

# ============================================
# SMART SHAREPOINT LIST MIGRATION SCRIPT
# ============================================

# --- Source (On-Premises) ---
$sourceWebURL = "https://sp2019.contoso.local/sites/Finance"
$sourceListName = "ExpenseClaims"
$spSourceWeb = Get-SPWeb $sourceWebURL
$spSourceList = $spSourceWeb.Lists[$sourceListName]
$spSourceItems = $spSourceList.GetItems()

# --- Destination (SharePoint Online) ---
$SiteURL = "https://contoso.sharepoint.com/sites/FinancePortal"
$ListName = "ExpenseClaims_Archive"
$AppId = "00000000-aaaa-bbbb-cccc-111111111111"
$AppSecret = "xyz123fakeappsecret987654321"
Connect-PnPOnline -Url $SiteURL -AppId $AppId -AppSecret $AppSecret
Get-PnPContext

# --- Process Each Item ---
foreach ($spSourceItem in $spSourceItems) {

    $firstName = $spSourceItem['First_x0020_Name']
    $lastName  = $spSourceItem['Last_x0020_Name']
    $email     = $spSourceItem['Email']
    $phone     = $spSourceItem['Phone_x0020_Number']

    # --- Check for Duplicate in Destination ---
    $existingItem = Get-PnPListItem -List $ListName -PageSize 2000 -Query @"
        <View>
            <Query>
                <Where>
                    <And>
                        <And>
                            <Eq><FieldRef Name='First_x0020_Name' /><Value Type='Text'>$firstName</Value></Eq>
                            <Eq><FieldRef Name='Last_x0020_Name' /><Value Type='Text'>$lastName</Value></Eq>
                        </And>
                        <And>
                            <Eq><FieldRef Name='Email' /><Value Type='Text'>$email</Value></Eq>
                            <Eq><FieldRef Name='Phone_x0020_Number' /><Value Type='Text'>$phone</Value></Eq>
                        </And>
                    </And>
                </Where>
            </Query>
        </View>
"@

    if ($existingItem.Count -gt 0) {
        Write-Host "Duplicate found for $firstName $lastName ($email) — deleting from source only." -ForegroundColor Yellow
        $spSourceItem.Delete()
        continue
    }

    # --- Copy to Destination ---
    Add-PnPListItem -List $ListName -Values @{
        "Title" = $firstName
        "LastName" = $lastName
        "Email" = $email
        "Phone" = $phone
        "Comments" = $spSourceItem['Comments']
        "MeetingDate" = $spSourceItem['Meeting_x0020_Date']
        "Region" = $spSourceItem['Region']
        "Processed" = $spSourceItem['Status']
    }

    Write-Host "Copied new item for $firstName $lastName ($email)." -ForegroundColor Green

    # --- Delete from Source After Copy ---
    $spSourceItem.Delete()
    Write-Host "Deleted source item for $firstName $lastName ($email)." -ForegroundColor Cyan
}

Write-Host "Migration completed successfully!" -ForegroundColor White -BackgroundColor DarkGreen

Step-by-Step Summary

  1. Source Connection – The script connects to the on-premises SharePoint site and fetches all items from the specified list.
  2. Destination Connection – Uses Connect-PnPOnline to authenticate with SharePoint Online via App ID and Secret.
  3. Duplicate Checking – For each item, it searches the destination list for matching data based on four identifying fields.
  4. Conditional Logic
    • If a duplicate is found → the item is deleted from the source only.
    • If not found → the item is copied to SharePoint Online and then removed from the source.
  5. Logging – Console messages display what’s being copied, skipped, or deleted in real time.

Why This Approach Works

  • Prevents duplicates in your target list.
  • Keeps data synchronized between on-premises and SharePoint Online.
  • Supports incremental migration—you can run it multiple times without re-importing the same records.
  • Cleans up automatically after successful copy, leaving no leftover data.

Important Considerations

  • The script deletes items from the source list after migration. Always test in a non-production environment first.
  • To perform a dry run, simply comment out the $spSourceItem.Delete() lines to verify results without removing anything.
  • Ensure your field internal names match between both lists.
  • Large lists may require pagination or indexing for better performance.

Potential Enhancements

This script forms a strong foundation for more advanced migration scenarios. Here are a few ideas to build upon it:

  • Export results or logs to a CSV file.
  • Handle attachments and lookup fields.
  • Add date filters to migrate only recent entries.
  • Introduce a “Test Mode” switch to simulate the run safely.

Final Thoughts

SharePoint migrations don’t have to be painful. By using PowerShell with smart checks, you can move your data confidently, ensure uniqueness, and maintain a clean, cloud-ready environment.

This particular script shows how automation and logic can work together to make SharePoint migrations faster, safer, and smarter.


Written by: Keyur Pandya
LinkedIn: https://www.linkedin.com/in/keyurbpandya/

Comments

Popular posts from this blog

Business Data Connectivity

I came to a requirement wherein I was supposed to get data from an 3 rd party portal using API’s and then bring them to SharePoint server. The first approach that I finalized was just to make BDC solution that will get data from 3 rd party portal and will deploy it to SharePoint. How to Create BDC solution in SharePoint? I found below link that is having really great description about hot to create and deploy the BDC solution to SharePoint. http://www.c-sharpcorner.com/uploadfile/hung123/creating-business-data-connectivity-service-using-visual-studio-2010/ After creating an POC I came to know that BDC model cannot be deployed on Multi tenant farm. So what can be done next? After some amount of googling I came to know that we can create BDC solution using WCF services also. So I created a WCF service solution that acted as a wrapper that used to fetch data from the portal. We can them publish that service to IIS or Server and use the servic...

Identity client runtime library (IDCRL) did not get a response from the login server.

Recently I was doing some testing with a background PowerShell and encountered a weird error. “Identity client runtime library (IDCRL) did not get a response from the login server”. The error that you might encounter while working with PowerShell. This error is very misleading when it comes to identifying what could go wrong. After doing quite a good amount of research below are the probable causes for the error. Invalid Credentials MFA (Multi-Factor Authentication) Manage security defaults. Solutions Invalid Credentials Check if your credentials are wrong. Especially if you are using variables. MFA (Multi-Factor Authentication) Check if MFA is enabled on the account which you are using. These only affect you badly if you are developing PowerShell for a background Job. Go to Microsoft 365 admin center Users -> Active users -> Select the user -> Manage multifactor authentication -> Select the user -> Disable multi-factor authentication. M...

SharePoint Migration : This content database has a schema version which is not supported in this farm

Today one of my client was expecting to restore a SharePoint Site Collection from and Database that he already took as a backup.  I followed below steps.           1.        Imported content database to SQL of the farm where the site is to be restored.           2.        Created a web application.           3.        Visited manage content database, set the current database property to offline.           4.        Click on add a new content database.           5.        Set the name of the content database same as the database that is imported to SQL.   SharePoint gave me below error. “ This content database has a schema version which is not supported in this farm." I tried to use powershe...