Wednesday, 9 February 2011

Export and import/create site content types in SharePoint using PowerShell

In my previous article, I ran through how to export custom site columns from one site collection and import them into another site collection using PowerShell. In this article, I will be following the same process, but this time for copying site content types from one site collection to another.

As described previously, SharePoint Server 2010 does contain the new Content Type Hub feature for distributing site columns and content types across multiple site collections, but there still may be scenarios where the feature cannot be used – e.g., if using SharePoint Foundation, migrating columns and content types between farms, or for documenting an environment.

As with the previous site column article, we can use PowerShell to export the content type schema from a source site collection into an XML file, which can then be used to import the same content types into another site collection.

Please note (Part 1): The script used here assumes that you have already migrated the site columns used in the these content types to the destination site collection. You could, of course, write a combined script that covers exporting/importing both site columns and content types to ensure the whole process is dealt with as a one-click operation.

Please note (Part 2): The script only supports creating the content type in a destination site and associating the appropriate site columns to it. It does not copy across other features of the content type – e.g., workflow associations, information management policies, document template, etc. – although you could expand the script to support extra features, if required.

For this example, I have created the following site content types under the “Custom Content Types” group in my development site collection:

image

I have also added a required “Description” column to the “Company Document” content type (from which the other custom content types inherit) and an optional “Category” column to the “IT Document” content type.

The PowerShell script below will export these content types to an XML file called Script-SiteContentTypes.xml in the C:\Install folder. Note that the script looks at the group called “Custom Content Types” to ensure content types created by a standard SharePoint installation are not included in the export. You will need to ensure that appropriate custom group name(s) are specified in your script when exporting:

$sourceWeb = Get-SPWeb http://portal
$xmlFilePath = "C:\Install\Script-SiteContentTypes.xml"

#Create Export File
New-Item $xmlFilePath -type file -force

#Export Content Types to XML file
Add-Content $xmlFilePath "<?xml version=`"1.0`" encoding=`"utf-8`"?>"
Add-Content $xmlFilePath "`n<ContentTypes>"
$sourceWeb.ContentTypes | ForEach-Object {
    if ($_.Group -eq "Custom Content Types") {
        Add-Content $xmlFilePath $_.SchemaXml
    }
}
Add-Content $xmlFilePath "</ContentTypes>"

$sourceWeb.Dispose()

This script will generate an XML file similar to the one shown below.

image

Once you have the XML file, it can be used to import the content types into another site collection by using the script below. The first part of the script gets the destination Web URL and exported XML file:

$destWeb = Get-SPWeb http://portal/sites/migrationtest
$xmlFilePath = "C:\Install\Script-SiteContentTypes.xml"

The final part of the script cycles through each content type specified in the XML file, creates the content type with the exported description and group name, and finally reads in each column associated with the exported content type and wires them up to the new content type in the destination site collection, specifying if they are hidden or required columns during the process.

#Create Site Content Types
$ctsXML = [xml](Get-Content($xmlFilePath))
$ctsXML.ContentTypes.ContentType | ForEach-Object {

    #Create Content Type object inheriting from parent
    $spContentType = New-Object Microsoft.SharePoint.SPContentType ($_.ID,$destWeb.ContentTypes,$_.Name)
   
    #Set Content Type description and group
    $spContentType.Description = $_.Description
    $spContentType.Group = $_.Group
   
    $_.Fields.Field  | ForEach-Object {
        if(!$spContentType.FieldLinks[$_.DisplayName])
        {
            #Create a field link for the Content Type by getting an existing column
            $spFieldLink = New-Object Microsoft.SharePoint.SPFieldLink ($destWeb.Fields[$_.DisplayName])
       
            #Check to see if column should be Optional, Required or Hidden
            if ($_.Required -eq "TRUE") {$spFieldLink.Required = $true}
            if ($_.Hidden -eq "TRUE") {$spFieldLink.Hidden = $true}
       
            #Add column to Content Type
            $spContentType.FieldLinks.Add($spFieldLink)
        }
    }
   
    #Create Content Type on the site and update Content Type object
    $ct = $destWeb.ContentTypes.Add($spContentType)
    $spContentType.Update()
    write-host "Content type" $ct.Name "has been created"
}

$destWeb.Dispose()

Once the script has been run, the custom site content types exported from the original site collection will be present in the new site collection…

image

…with the “Description” and “Category” columns linked to them as expected.

image

26 comments:

  1. Perfect - just what i needed - THANKS.

    ReplyDelete
  2. Getting an error:
    Constructor not found for New-Object Microsoft.SharePoint.SPFieldLink

    ReplyDelete
  3. I'm having the same issue as user before me: New-Object : Constructor not found. Cannot find an appropriate constructor for type Microsoft.SharePoint.SPFieldLink.
    At C:\Scripts\ImportCT.ps1:19 char:38

    Any ideas, please?

    ReplyDelete
    Replies
    1. I had the same issue and found that the problem was with a feature not activated.

      In my scenario the content type was based off the "Document" content type and I had "Document ID Service" turned on in the source site collection features. I turned on the feature in my destination site collection and deleted the previously imported content types. I re-ran the import again with no errors.

      thanks for the script Phil!

      Delete
    2. Chandra Shekhar24 April 2012 08:19

      You will face this issue if you have not imported the "Site Columns" to destination web before importing the content types. Please go thru the previous article "http://get-spscripts.com/2011/01/export-and-importcreate-site-columns-in.html" for importing the "Site Columns".

      Thanks Phil for the contribution :)

      Delete
  4. Wonderful blog! I found it while searching on Yahoo News. Do you have any tips on how to get listed in Yahoo News? I’ve been trying for a while but I never seem to get there! Many thanks.sbobet

    ReplyDelete
  5. Thanks allot, it works like a charm.
    Cheers
    Alex

    ReplyDelete
  6. This comment has been removed by a blog administrator.

    ReplyDelete
  7. Great help! I'm working through the SPFiledLink error mentioned above as well (it's not the DocumentID service, but is likely some other dependency). In any case, it's helpful to have a way to clear the incomplete content types so I can try again. Here's a script to do that:

    Of course, this will delete all content types for the $group specified. Hope you are using groups effectively!

    $sourceWeb = Get-SPWeb http://yourdestsite;
    $group = "your group name";

    for ($i=$sourceWeb.ContentTypes.Count; $i -gt 0; $i--)
    {
    $thisType = $sourceWeb.ContentTypes[$i - 1];
    if ($thisType.Group -eq $group) {
    $sourceWeb.ContentTypes.Delete($thisType.Id);
    }
    }

    ReplyDelete
  8. Thanks for the contribution, dfosterh!

    ReplyDelete
  9. Thanks for the powershell script, I have a question.
    Normally the schema for content type will not include those columns that from parent.
    just like below, with this script parent columns will also include in the output xml file.
    result my document library display form showing duplicate name and title columns.
    Should I remove those columns manually or I'm doing something wrong?

    ReplyDelete
  10. Hello, thank you for putting up this information. One thing I'd like to do is export information about custom content types to an xml file in order to keep track of them. As far as I can tell there is no data on a content type's parent type in the xml generated by your solution. Could you advise me on how to accomplish this?

    ReplyDelete
  11. Phil

    Thanks for sharing this wonderful article.

    We have list out own custom content type for different sites and their document library. How can I import my own custom content type and set it for each assigned document library.

    Please advise

    Avian

    ReplyDelete
  12. Thank you for the post. The script works for the top level site i.e http://portal but does not return any results for http://portal/testing/ear which is the top level site of a site collection.

    ReplyDelete
  13. I have a custom group and have a custom content type in that group. Script above doesn't work for me. what should I need to change to make sure I can export and then import the content type.

    My custom content type name: Informatics General Documents
    My custom group name: Informatics Content Types

    Please advise.
    Mdeveloper

    ReplyDelete
  14. Helped to solve a massive issue for me. Thank you.

    ReplyDelete
  15. Very helpful series of posts. It would be more helpful if your XML file was downloadable or text-selectable so I could see more of it. I'm hacking this series to get content types and columns that were deployed as features to 2007 imported into the syndication hub of 2010. Getting my XML right is proving to be the only real issue.

    ReplyDelete
  16. Greetings from the nordics, you save my Friday! Thanks!

    ReplyDelete
  17. Is this code work for sharepoint 2007? I think there is a problem with SpContenttype constructor.
    Plz suggest a right way to go with 2007.

    ReplyDelete
  18. Excellent piece of work - thanks Phil!

    ReplyDelete
  19. Thanks, but doesn't work for me, gives me an empty xml file.

    Please help

    ReplyDelete
  20. Thanks! Works great
    What about Document Set? is that possible?

    ReplyDelete
  21. Thank you again! You are appreciated!

    I didn't get the results I expected on this or the Custom Columns script on the first try, but realized that I had to change the "Custom List" to "{customized name of client} Custom List" and then got the right xml! Wonderful!

    Doug
    Codesigned.com

    ReplyDelete
  22. Thanks, just one question; will this procedure work if I'm importing/exporting content types from one farm to another?

    thank you.

    ReplyDelete