PortiBlog

Change Content Type on SharePoint List with PowerShell

1 april 2015

We encountered a problem with a content type on a document library. We were unable to modify the content type, change the column order or add/delete columns.

By removing and adding the content type again, the problem would be solved. However, you cannot remove a content type that is in use.

The following PowerShell code is able to replace the content type in a document library with another content type. It will remove the faulty content type from the list and add the content type again. This is done by adding a temporary content type based on the old one and setting the content type of all items (which are using the faulty content type) in the document library to the temporary content type. After the faulty content type is re-added all the items are set back to this content type and the temp content type will be removed.

If an item has another content type, this item will not be processed. If a library requires checking out items before editing, the script will check out the item. After the change is made, the script will perform a Check in and checks if an item needs approval, and of course approves the item.

All the script needs is url, list name, name of the old content type and the name of the new content type.

You are able to give it as parameter, example:
.\ChangeContentType.ps1 –web <url> –list <list name> -OldCT <old CT name> -NewCT <new CT name>

When no parameters are provided the script will ask for them before running.

If you want to replace the content type with the same one, then use as old and new CT name, the same name. It OldCT and NewCT are different the script will add the new one and replace the content type on the items with the new one. If content type doesn’t exist, the script will run into errors.

A transcript will be made and places in the Temp folder on the C-drive. The name of the transcript will contain a date and timestamp, so you’re able to run the script multiple time without overwriting the transcript log.


param (
  [string]$web = $( Read-Host "Input URL of web, please" ),
  [string]$list = $( Read-Host "Input Listname, please" ),
  [string]$OldCT = $( Read-Host "Input old Content type, please" ),
  [string]$NewCT = $( Read-Host "Input new Content type, please" )
)

If ((Get-PSSnapin |?{$_.Name -eq "Microsoft.SharePoint.PowerShell"})-eq $null) {
   $PSSnapin = Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue | Out-Null
}

start-transcript -Path c:\temp\Transcript_ChangeContentType_$(get-date -f yyyy-MM-dd_HHmmss).log

$dummy = $false
if ($OldCT -eq $NewCT) { $dummy = $true }

function ApproveItem ($ItemToApprove)
{
    if($ItemToApprove.ListItem.List.EnableModeration)
    {
        $ItemToApprove["_ModerationStatus"] = 0
        $ItemToApprove.Update()
    }
    else
    {
        write-host $ItemToApprove.Title"("$ItemToApprove.Name") does not require approval in this list"
    }
}

function AddContentType ($Addweb, $lib, $ct)
{
    write-host "Adding content type" $ct.Name 
    $lib.ContentTypesEnabled = $true
    $lib.Update()

    #Add Web content types to the list
    $ctToAdd = $Addweb.availablecontenttypes[$ct.Name]
    if (!$lib.ContentTypes[$ctToAdd.Name])
    {
        $ct1 = $lib.ContentTypes.Add($ctToAdd)
        write-host "Content type" $ct1.Name "added to list" $lib.Title
        $lib.Update()
    }
}

function AddFieldsToCT ($old, $ct, $Addlist)
{
    write-host "Adding fields to new content type"
    $cts = $Addlist.contenttypes
    $ctAddFields = $ct
    ForEach ($id in $cts)
    {
        if ($id.Name -eq $old.Name)
        {
            ForEach ($field in $id.Fields)
            {
                $name = $field.Title
                if ($ctAddFields.FieldLinks[$name])
                {
                    Write-host "Field already exists:" $name
                }
                else
                {
                    write-host "Field has to be linked:" $name
                    $fieldToAdd = $Addlist.Fields[$field]
                    $fieldLink = new-object Microsoft.SharePoint.SPFieldLink($fieldToAdd)
                    $ctAddFields.Fieldlinks.Add($fieldLink)
                    $ctAddFields.update()
                }
            }
        }
    }
    $Addlist.Update()
}
function ChangeCTonItems ($ItemsLib, $NewCTItems, $OldCTItems)
{
    write-host "Changing Content type of items"
    $items = $ItemsLib.Items
    $CTid = $NewCTItems.id
    $OldId = $OldCTItems.id
    foreach ($item in $items)
    {
        if ($item["ContentTypeId"] -eq $OldId)
        {
            if ($ItemsLib.ForceCheckout -eq $true)
            {
                $item.checkout()
            }
            $item["ContentTypeId"] = $CTid
            $item.Update()
            write-host $item.Name Updated
            if ($ItemsLib.ForceCheckout -eq $true)
            {
                $item.checkin("Corrected content type", [Microsoft.SharePoint.SPCheckinType]::MajorCheckIn)
            }
            if ($ItemsLib.EnableModeration -eq $true)
            {
                ApproveItem $item
            }
        }
    }
}
function RemoveCT ($listCtremoval, $CTtoRemove)
{
    $CTremoval = $listCtremoval.ContentTypes[$CTtoRemove]
    $CTRemoveID = $CTremoval.Id
    write-host "Removing content type" $CTtoRemove "from list" $listCtremoval.Title
    $listCtremoval.ContentTypes.Delete($CTRemoveID)
    $listCtremoval.Update()
}

function AddFieldsToListCT ($old, $ct, $DocToAdd)
{
    write-host "Adding fields to new content type"
    $cts = $DocToAdd.contenttypes
    $CTtype = $DocToAdd.ContentTypes[$ct]
    ForEach ($id in $cts)
    {
        if ($id.Name -eq $old.Name)
        {
            ForEach ($field in $id.Fields)
            {
                $name = $field.Title
                if ($CTtype.FieldLinks[$name])
                {
                    Write-host "Field already exists:" $name
                }
                else
                {
                    write-host "Field has to be linked:" $name
                    $fieldToAdd = $DocToAdd.fields.getfield($field)
                    $fieldLink = new-object Microsoft.SharePoint.SPFieldLink($fieldToAdd)
                    $CTtype = $DocToAdd.ContentTypes[$ct]
                    $CTtype.fieldlinks.add($fieldLink)
                    $CTtype.Update()
                }
            }
        }
    }
}

Function RemoveCTFromSite ($siteUrl, $CTtoRemoveFromSite)
{
    $removeThis = $siteUrl.ContentTypes[$CTtoRemoveFromSite]
    $removeThis.Delete()
}

$spWeb = Get-SPweb $web
Write-host "Begin changing content type..."
$docLibrary = $spWeb.Lists[$list]
$OldCT1 = $spWeb.availablecontenttypes[$OldCT]
$NewCT1 = $spWeb.availablecontenttypes[$NewCT]

if ($docLibrary -ne $null)
{
    if($dummy -eq $true)
    {
        write-host Readding Conten type $OldCT1.Name using a dummy
        $ctypeName = "Temp dummy Content Type"
        $ctypeParent = $spWeb.availablecontenttypes[$OldCT1.Name]
        $ctype = new-object Microsoft.SharePoint.SPContentType($ctypeParent, $spWeb.contenttypes, $ctypeName)
        $spWeb.contenttypes.add($ctype) > $null
        AddFieldsToCT $OldCT1 $ctype $docLibrary
        AddContentType $spWeb $docLibrary $ctype 
        ChangeCTonItems $docLibrary $ctype $docLibrary.ContentTypes[$OldCT1.Name]
        RemoveCT $docLibrary $OldCT1.Name
        AddContentType $spWeb $docLibrary $NewCT1
        AddFieldsToListCT $ctype $NewCT1.Name $docLibrary
        ChangeCTonItems $docLibrary $docLibrary.ContentTypes[$NewCT1.Name] $docLibrary.ContentTypes[$OldCT1.Name]
        RemoveCT $docLibrary $ctype.Name
        RemoveCTFromSite $spWeb $ctype.Name
    }
    else
    {
        write-host Change Content type from $OldCT1.Name to $NewCT1.Name
        AddFieldsToCT $OldCT1 $NewCT1 $docLibrary
        AddContentType $spWeb $docLibrary $NewCT1
        ChangeCTonItems $docLibrary $docLibrary.ContentTypes[$NewCT1.Name] $docLibrary.ContentTypes[$OldCT1.Name]
        RemoveCT $docLibrary $OldCT1
    }
    
}
else
{
    write-host "The list" $lookForList "does not exist in site" $spWeb.Title
}
 

Stop-transcript

Submit a comment