Tuesday, 9 November 2010

Add and remove site content types from SharePoint lists using PowerShell

If you’ve ever been involved in a content type redesign, you’ll know how much of a pain it can be to add new site content types on a large number of existing lists, as well as removing those content types no longer needed. To try and ease the pain, in this article I have provided some example scripts on how to bulk add and remove site content types from lists using PowerShell.

Note that the scripts do not create the site content types for you – they assume that the content types are already created in the root site of the site collection containing the lists to be modified.

I have provided scripts based on a couple of scenarios:

1) Checking each site in a site collection and changing content types associated on lists with the same name – e.g., add or remove a specific content type from all document libraries called “Shared Documents”

2) Checking each site in a site collection and changing content types based on the content types already associated on lists – e.g., add or remove a content type from any document library which currently includes the “Sales Document” content type

Adding content types to lists

The first content type adding script performs these tasks:

  • Sets up variables for connecting to the site collection and specifying the name of the document library to examine in each site 
  • Uses a piped command to walk through each site in the site collection and:
    • Attach to the document library specified in the $lookForList variable (“Shared Documents” in the example script below)
    • Enable the “Allow management of content types” option on the list (you can remove this option if already set on the document library)
    • Add the “Sales Document” and “IT Document” content types to the document library
    • Output progress to the console for reference
  • Dispose of the site object to free up server resources

#Get site object and specify name of the library to look for in each site
$site = Get-SPSite http://portal
$lookForList = "Shared Documents"

#Walk through each site and change content types on the list specified
$site | Get-SPWeb -Limit all | ForEach-Object {
   
    write-host "Checking site:"$_.Title
   
    #Make sure content types are allowed on the list specified
    $docLibrary = $_.Lists[$lookForList]
   
    if ($docLibrary -ne $null)
    {
        $docLibrary.ContentTypesEnabled = $true
        $docLibrary.Update()
   
        #Add site content types to the list
        $ctToAdd = $site.RootWeb.ContentTypes["Sales Document"]
        $ct = $docLibrary.ContentTypes.Add($ctToAdd)
        write-host "Content type" $ct.Name "added to list" $docLibrary.Title
        $ctToAdd = $site.RootWeb.ContentTypes["IT Document"]
        $ct = $docLibrary.ContentTypes.Add($ctToAdd)
        write-host "Content type" $ct.Name "added to list" $docLibrary.Title
        $docLibrary.Update()
    }
    else
    {
        write-host "The list" $lookForList "does not exist in site" $_.Title
    }
}
#Dispose of the site object
$site.Dispose()

An example from the output of this script is shown below:

image

The second content type adding script performs the following tasks:

    • Sets up variables for connecting to the site collection and specifying the name of the content type to examine on all document libraries in each site 
    • Uses a piped command to walk through each site in the site collection and:
      • Get each document library in the site and check if a content type exists with the name specified for the $lookForCT variable (“Sales Document” in the example script below)
      • If the $lookForCT content type exists on the library, add the “HR Document” and “IT Document” content types to the document library
      • Output progress to the console for reference
    • Dispose of the site object to free up server resources

#Get site object and
#specify name of the content type to look for in each library
$site = Get-SPSite http://portal
$lookForCT = "Sales Document"

#Walk through each site in the site collection
$site | Get-SPWeb -Limit all | ForEach-Object {
   
    write-host "Checking site:"$_.Title
   
    #Go through each document library in the site
    $_.Lists | where { $_.BaseTemplate -eq "DocumentLibrary" } | ForEach-Object {
       
        write-host "Checking list:"$_.Title
       
        #Check to see if the library contains the content type specified
        #at the start of the script
        if (($_.ContentTypes | where { $_.Name -eq $lookForCT }) -eq $null)
        {
            write-host "No content type exists with the name" $lookForCT "on list" $_.Title
        }
        else
        {
            #Add site content types to the list
            $ctToAdd = $site.RootWeb.ContentTypes["HR Document"]
            $ct = $_.ContentTypes.Add($ctToAdd)
            write-host "Content type" $ct.Name "added to list" $_.Title
            $ctToAdd = $site.RootWeb.ContentTypes["IT Document"]
            $ct = $_.ContentTypes.Add($ctToAdd)
            write-host "Content type" $ct.Name "added to list" $_.Title
            $_.Update()
        }
    }
}
#Dispose of the site object
$site.Dispose()

An example of the output from the script is shown below:

image

Removing content types from lists

The first content type removal script performs these tasks:

  • Sets up variables for connecting to the site collection and specifying the name of the document library to examine in each site 
  • Uses a piped command to walk through each site in the site collection and:
    • Attach to the document library specified in the $lookForList variable (“Shared Documents” in the example script below)
    • Remove the “Sales Document” and “IT Document” content types from the document library
    • Output progress to the console for reference
  • Dispose of the site object to free up server resources

#Get site object and specify name of the library to look for in each site
$site = Get-SPSite http://portal
$lookForList = "Shared Documents”

#Walk through each site and change content types on the list specified
$site | Get-SPWeb -Limit all | ForEach-Object {
   
    write-host "Checking site:"$_.Title
   
    #Check list exists
    $docLibrary = $_.Lists[$lookForList]
   
    #Remove unwanted content types from the list
    if($docLibrary -ne $null)
    {
        $ctToRemove = $docLibrary.ContentTypes["IT Document"]
        write-host "Removing content type" $ctToRemove.Name "from list" $docLibrary.Title
        $docLibrary.ContentTypes.Delete($ctToRemove.Id)
        $docLibrary.Update()
    }
    else
    {
        write-host "The list" $lookForList "does not exist in site" $_.Title
    }
}
#Dispose of the site object
$site.Dispose()

An example of the output from the script is shown below:

image

Finally, the second content type removal script performs the following tasks:

    • Sets up variables for connecting to the site collection and specifying the name of the content type to examine on all document libraries in each site
    • Uses a piped command to walk through each site in the site collection and:
      • Get each document library in the site and check if a content type exists with the name specified for the $lookForCT variable (“Sales Document” in the example script below)
      • If the $lookForCT content type exists on the document library (“Sales Document” in the example script below), remove it
      • Output progress to the console for reference
    • Dispose of the site object to free up server resources

#Get site object and
#specify name of the content type to look for in each library
$site = Get-SPSite http://portal
$lookForCT = "Sales Document"

#Walk through each site in the site collection
$site | Get-SPWeb -Limit all | ForEach-Object {
   
    write-host "Checking site:"$_.Title
   
    #Go through each document library in the site
    $_.Lists | where { $_.BaseTemplate -eq "DocumentLibrary" } | ForEach-Object {
       
        write-host "Checking list:"$_.Title
       
        #Check to see if the library contains the content type specified
        #at the start of the script
        if (($_.ContentTypes | where { $_.Name -eq $lookForCT }) -eq $null)
        {
            write-host "No content type exists with the name" $lookForCT "on list" $_.Title
        }
        else
        {
            #Remove content types from list
            $ctToRemove = $_.ContentTypes[$lookForCT]
            write-host "Removing content type" $ctToRemove.Name "from list" $_.Title
            $_.ContentTypes.Delete($ctToRemove.Id)
            $_.Update()
        }
    }
}
#Dispose of the site object
$site.Dispose()

An example of the output from the script is shown below:

image

Note that a content type cannot be removed from a list if there are items currently using it in that list. Therefore, before you can attempt to remove a list content type, you must make sure that any items associated with it have either been assigned a different content type (see this article for details on how to do this) or deleted from the list completely.

Even after you think that all list items have been reassigned new content types or deleted, there still may be reasons you get the dreaded “Content type is still in use” message when trying to remove the content type. This is usually because there are still items present in the list that you are not able to see in standard list views. Here are a few tips to troubleshoot the message if you are still getting it:

  • Go to the document library showing the error, click Library Settings from the Library tab on the ribbon interface and then select Manage files which have no checked in version. You can use this administration page to take ownership of files created or uploaded by users but not checked in yet, and therefore invisible in list views. Once you have taken ownership, you can check them in and reassign the content types set on them
  • Check the recycle bin and delete files using the content type you wish to remove from the list
  • Remove any old versions of a document which may have used the content type you wish to remove from the list

18 comments:

  1. Hi Phil,

    This Powershell script is amazing, just what I needed. Do you know if it is possible to control the visibility of the Content Types when you add them.

    Peter

    ReplyDelete
  2. Control visibility in what sense?

    ReplyDelete
  3. In a document library under content types, there is the option to "Change new button order and default content type". I was wondering if your script could be modified to set whether the Content Type was Visible or Not on the New Button.

    ReplyDelete
  4. Hi Phil,
    Can you please drop a note on how I can remove the defaul blog which appears when I add Out of box Recent Blog Posts from mysite

    Thanks

    ReplyDelete
  5. Hi Phil,

    To be more clear..
    I have created one blog site in SharePoint 2010 MySite. When I am going into blog site there is one default Post will be available like "Welcome to your blog." I want to delete this default blog post "Welcome to your blog." with the help of PowerShell script.

    ReplyDelete
  6. "Anonymous" - You can certainly do it in PowerShell by walking through the blog site of each My Site, attaching to the posts library and deleting the aspx file in question - I have no time to do it for you I'm afraid. Sorry.

    ReplyDelete
  7. Thanks Phil. I was able to do it in c#. I will later do it in ps.

    ReplyDelete
  8. Hi Phil

    I tested the code for adding content type, I am getting following error, please let me know what I am missing


    Exception calling "Add" with "1" argument(s): "Object reference not set to an instance of an object."
    At C:\script\Add-SPSiteContentType1.ps1:21 char:43
    + $ct = $docLibrary.ContentTypes.Add <<<< ($ctToAdd)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    ReplyDelete
  9. Hello

    I used remove script for deleting content type from the list and its working fine. Now my problem is that content type also has associated 4 different type columns, they are not deleting automatically from the list, they are still exist as a individial column.

    Let me how can I do this

    Regards
    Avian

    ReplyDelete
  10. Cheap Lebron Shoes,Cheap Lebron 13 Sale,Air Max 2016 Sale,Cheap Air Max 2015 shoes are launched with new style and top quality.Cheap Air Max 2016 Shoes have become the most popular of Sport shoes.It Absolutely the best Christmas gift to her favorite things.
    [url=http://www.cheaplebron13sale.com]Nike Air Max 2016[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max 2015[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max 2014[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max 2013[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max 95[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max 90[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max Thea[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max Motion[/url]
    [url=http://www.cheaplebron13sale.com]Nike Air Max Tailwind 7[/url]
    [url=http://www.cheaplebron13sale.com]Nike Flyknit Air Max[/url]
    [url=http://www.cheaplebron13sale.com]Cheap LeBron 13[/url]
    [url=http://www.cheaplebron13sale.com]Cheap LeBron 12[/url]
    [url=http://www.cheaplebron13sale.com]Cheap Kobe 11[/url]
    [url=http://www.cheaplebron13sale.com]Cheap Kobe 10[/url]
    [url=http://www.cheaplebron13sale.com]Cheap Kobe 9[/url]
    [url=http://www.cheaplebron13sale.com]Cheap Jordan 5[/url]
    [url=http://www.cheaplebron13sale.com]Cheap Jordan 11[/url]
    [url=http://www.cheaplebron13sale.com]Cheap Jordan 13[/url]
    [url=http://www.cheaplebron13sale.com]Cheap Nike Free 5.0[/url]
    [url=http://www.cheaplebron13sale.com]Nike Free 5.0[/url]

    ReplyDelete