How to unpublish a published content type if the published content type no longer exists

One of my colleagues (Steffi Buchner) recently got a case where a customer deleted a content type hub and later noticed that some of the content types provided by this hub were already published.

The problem is that the information about which content types are published is stored in the TermStore database outside of the content type hub – leading to orphan published content types.

If you create a new site collection now you will notice that the content types earlier published by the now deleted content type hub show up as subscribed content types.

How can you get rid of such an orphan content type? This is now an hen and egg problem: to unpublish a content type you need to go to the content type hub, select the content type and unpublish it. As the content type hub no longer exists it is not possible use this option. The same applies if only the content type in the content type hub has been deleted without unpublishing it.

Note: there is no extra check in the content type hub which would prevent you from deleting a content type which is already published or which would force it to be unpublished. The same applies to deleting a content type hub. You can delete it even if there are still content types being published from the content type hub. 

After some research my colleague identified a nice workaround: the API used to unpublish a content type does not really bother about whether it is being called on the content type object has been retrieved from the content type hub or in one of the subscribed site collections. The workaround requires an existing content type hub. So if you deleted the hub you would need to create a new one to apply the workaround – after all content types are unpublished you can delete it again if required.

Below is the powershell script that can be used to unpublish orphan published content types:

Add-PSSnapIn Microsoft.SharePoint.PowerShell

if ($args.Count -ne 3)
{
   Write-Host "UnpublishContentTypes.ps1 <web url> <content type hub url> <unpublish>"
   exit
}

$webUrl = $args[0]
$ctUrl = $args[1]
$unpublish = $args[2]

$web = Get-SPWeb $webUrl
$ctsite = Get-SPSite $ctUrl
$ctPublisher = New-Object Microsoft.SharePoint.Taxonomy.ContentTypeSync.ContentTypePublisher($ctsite)

foreach($ct in $web.ContentTypes)
{
    if ( $ct.XmlDocuments -like "*SharedContentType*")
    {
        try
        { 
            if (-not $ctsite.RootWeb.ContentTypes[$ct.Name])
            {
                Write-Host "Found orphan Shared ContentType $($ct.Name) – ($($ct.ID))"
             
                if($unpublish)
                {
                    $ctPublisher.UnPublish($ct)
                    Write-Host "$($ct.Name) – ($($ct.ID)) UnPublished successfully"
                }
            }
        }
        catch
        {
            Write-Host "Error unpublishing ContentType $($ct.Name) – ($($ct.ID)): $error[0]"
        }
    }
}

if($unpublish)
{
    Start-SPTimerJob MetadataSubscriberTimerJob
}

7 Comments


  1. One of my colleagues (Steffi Buchner) recently got a case where a customer deleted a content type hub

    Reply

  2. oh my… using $args for input handling… that's bad

    you should use
    param (
    [Microsoft.SharePoint.Powershell.SPWebPipeBind]$Web,
    [Microsoft.SharePoint.Powershell.SPSitePipeBind]$PublishingSiteCollection
    [switch]$Unpublish
    )

    Use SPWebPipeBind and SPSitePipeBind to let the user pass the url or an SPSite/SPWeb object from the pipeline (use $spWeb = $Web.Read() to get the actual SPWeb)

    Reply

  3. Hi Piotr,

    excellent comment! You are correct, that would be a much cleaner implementation.

    Cheers,
    Stefan

    Reply

  4. how do i get this script to run? it just askes me to save?? im not very good with power shell
    i deleted a content type from the hub without unpublishing it first

    Reply

    1. Hi Alz,
      you need to add the script to a text file named something with file extension .ps1 – e.g. myscript.ps1
      Then open the SharePoint management shell and run this script by going to the directory where the script file is located and execute it by adding “.\” in front of the command.
      E.g.:
      PS> .\myscript.ps1
      Cheers,
      Stefan

      Reply

  5. is this applicable for sharepoint online… what should be the in the below code
    {
    Write-Host “UnpublishContentTypes.ps1 ”
    exit

    Reply

  6. Any chance some one knows how to get rid of orphaned content types in SharePoint online? have a client and they deleted the content types without unpublishing them from the hub. – now they keep coming back.

    Reply

Leave a Reply

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