Back

Update list to use content type

Nov 10, 2024 min read

How To Add a Content Type After the Fact in SharePoint πŸ’‘

We’ve all tried creating a SharePoint list without using Content Types from the start. It seems like the quick solution, but it can lead to challenges later when restructuring the list. This post explains why using Content Types from the beginning is a smart move that can save time and hassle in the long run.

This has been a recurring issue for me πŸ˜… – countless times I’ve started a SharePoint list without Content Types, only to realize later that I needed the list for tasks like search πŸ” or advanced filtering. And, of course, it usually happens when the list is already full of data πŸ“Š without any associated Content Type, making it even more challenging πŸ› οΈ to get everything to work smoothly.

⚠️ Disclaimer: This will only work if the columns in the Content Type match those already present in the list.

How Do I Fix It? πŸ€”

The first step is, of course, to create a content type. Once it’s created, I then export it as a template using the PnP PowerShell command Get-PnPSiteTemplate πŸ’». I make sure that only the content type is included in the XML file πŸ“‚.

Once the PnP template is ready, a PowerShell script I created can be used to fix this issue – though it can’t handle all scenarios. The script includes the following variables, which need to be filled out:

$siteUrl = "https://xxx.sharepoint.com/sites/xxx"
$listName = ""
$contentTypeName = ""
$columnsToMap = @("...")  # Replace with the actual column names
$userFields = @("...")  # Replace with actual user field names if needed
$templatePath = "..\ContentTypeTemplate.xml";

What the script does is fairly simple πŸ› οΈ – I load all rows with their values into memory 🧠, remove the columns ($columnsToMap) that need to be deleted πŸ—‘οΈ, then invoke the PnP template containing the content type. Finally, I reload all values into the new columns. Since they have the same names as the old columns, everything loads smoothly βœ….

# Connect to SharePoint Online
Connect-PnPOnline -Url $siteUrl -Interactive

# Enable content type management on the list
Set-PnPList -Identity $listName -EnableContentTypes $true
Write-Host "Content types enabled on the list."

# Backup data from old columns
$items = Get-PnPListItem -List $listName -PageSize 2000
$backupData = @{}

foreach ($item in $items) {
    $itemData = @{}
    # Backup old column data
    foreach ($column in $columnsToMap) {
        $itemData[$column] = $item[$column]
    }
    $backupData[$item.Id] = $itemData
}

# Remove old columns
foreach ($column in $columnsToMap) {
    Remove-PnPField -List $listName -Identity $column -Force
    Write-Host "Removed old column:" $column
}

# Apply PnP Provisioning Template
Invoke-PnPSiteTemplate -Path $templatePath
Write-Host "PnP template applied to the site."

# Get the content type
$contentType = Get-PnPContentType -Identity $contentTypeName

# Add the content type to the list
Add-PnPContentTypeToList -List $listName -ContentType $contentType
Write-Host "Content type added to the list."

# Update items to the new content type and restore data to new columns
foreach ($item in $items) {
    $itemId = $item.Id
    $itemData = $backupData[$itemId]
    
    # Handle user fields
    foreach ($userField in $userFields) {
        if ($itemData[$userField]) {
            $UserDto = $itemData[$userField];
            write-host "User: " $UserDto.Email

            $itemData[$userField] = $UserDto.Email
        }
    }

    # Update item content type
    Set-PnPListItem -List $listName -Identity $itemId -Values @{"ContentTypeId" = $contentType.Id }
    
    # Restore data to new columns
    Set-PnPListItem -List $listName -Identity $itemId -Values $itemData
    Write-Host "Updated item ID:" $itemId
}

Write-Host "All items updated to the new content type and old columns removed."

# Disconnect from SharePoint Online
Disconnect-PnPOnline

As mentioned earlier, this script doesn’t solve everything. For example, any views created with the old columns will no longer work, even if the new columns have the same name. So, there’s definitely room for improvement in my script.

That said, the script has saved me quite a bit of manual work multiple times πŸ™Œ.

Jeppe Spanggaard

A passionate software developer. I love to build software that makes a difference!