Renaming an In-Use Content Type in SharePoint Online

Design of SharePoint content Types for SharePoint, and in particular SharePoint Online is very important. Care must be taken to ensure that the design is appropriate for the environment as changes made later can impose significant management overheads. In particular, if a Content Type is put to use (I.e. is assigned to a list/library), this can complicate changes made at a point following initial deployment.

Some Content Type operations are simple, e.g. adding a column. This will work as expected, with the new column rippling all the way down to the in-use Content Types.

Renaming a Content Type potentially falls under the ‘more difficult’ category, in particular if it’s been assigned to a list/library. This is due to the way that SharePoint handles this process, with the Content Type that is assigned to the list/library being a child content type of that published to a site collection.

I’d still strongly recommend using the Content Type Hub (hidden site collection, available on /sites/contenttypehub) to centrally manage and publish content types. A change to the name of a content type made here, then the content type being republished will rename the content type in the content type gallery in each site collection. If the content type is attached to a list/library however as this is a child content type, this will not be renamed, so you end up in the scenario that the gallery reflects the name change, while the instance attached to the list/library does not.

Looking at the list of content types attached to a list/library, and clicking through on the content type that you wish to change does allow you to change the content type from read-only to writeable. This then allows you to change the content type’s name, however if you have lots of libraries and/or lots of content types to process, this gets laborious very quickly. PowerShell to the rescue again!

The following script is a sample that can be used to change the name of a content type that is attached to a set of lists/libraries:

$SiteUrl = "https://domain.sharepoint.com/teams/SiteCollection"  
$UserName = "Andy@o365domain.com"  
# Ask the user for the password
$Password = Read-Host -Prompt "Enter your password: " -AsSecureString

# List of lists/libraries to process
$libraries = @("Library1","Library2","Library3")

# Add references to the CSOM libraries
Add-Type -Path "C:\<Path-to-CSOM-libraries>\Microsoft.SharePoint.Client.dll" 
Add-Type -Path "C:\<Path-to-CSOM-libraries>\Microsoft.SharePoint.Client.Runtime.dll" 

# Connect
$spoCtx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)  
$spoCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $Password)   
$spoCtx.Credentials = $spoCredentials

# Load the web context
$web = $spoCtx.web
$spoCtx.load($web)
$spoCtx.executeQuery()

# Process the lists/libraries
foreach ($lib in $libraries) {
    $list = $web.lists.getbytitle("$lib")
    $spoCtx.load($list)
    $spoCtx.executeQuery()

    # Load the content types attached to the list/library
    $CTs = $list.ContentTypes
    $spoCtx.load($CTs)
    $spoCtx.executeQuery()

    $IDToUse = ""

    Write-Host "Processing library $lib" -ForegroundColor Yellow
    foreach ($CT in $CTs) 
    { 
        Write-Host "-- " $CT.Name $Ct.Id
        if ($CT.Name -eq "Content Type To Change")
        {
            $IDToUse = $CT.Id
            Write-Host "Using this one..." -ForegroundColor Green
        }
    }

    # Grab a reference to the content type we want to change
    $CT = $list.ContentTypes.getbyid($IDToUse)
    $spoCtx.load($CT)
    $spoCtx.executeQuery()

    if ($CT -ne $null)
    {
        # Set the content type to be writeable to be able to update it
        Write-Host "Setting content type to ReadOnly = false" -ForegroundColor Green
        $CT.ReadOnly = $false
        $CT.Update($false)
        $spoCtx.load($CT)
        $spoCtx.executeQuery()

        # Modify the content type name
        Write-Host "Processing Content type..." -ForegroundColor Cyan
        $CT.Name = "Content Type That Has Been Changed"
        $CT.Update($false)
        $spoCtx.load($CT)
        $spoCtx.executeQuery()

        # Return the content type to read-only
        Write-Host "Setting content type to ReadOnly = true" -ForegroundColor Green
        $CT.ReadOnly = $true
        $CT.Update($false)
        $spoCtx.load($CT)
        $spoCtx.executeQuery()
    }
}