I've moved my blog to!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Thursday, August 7, 2008

Setting List Content Types using STSADM

Sometimes when I'm working on a new Feature I find it easier to take certain snippets that I need to test and pull them out into custom STSADM commands.  This enables me to quickly and easily test the core code and without having to go through all the deployment steps.  It was for this purpose that I originally created this new command, gl-setlistcontenttypes.  I did find later that the command ended up being real useful in a scripted deployment that I'm working on so I managed to knock out a well tested new command and some reusable code for a Feature that I'm working on.

The code is really simple - I've got a primary method, SetContentTypes, which takes in 3 string arrays containing the content types to remove and add as well as another array for the new button order.  There's also a couple of helper methods that are called.  I then just loop through each array and call the necessary methods (Add or Delete) on the ContentTypes property which returns an SPContentTypeCollection object.  The only tricky part is setting the order of the content types - this is done via RootFolder property.  There's a UniqueContentTypeOrder property that must be set to an IList<SPContentType> object.  Manipulating the IList object directly will not work as it does not set the dirty flag and therefore the Update() method will appear to do nothing so you must create a new object and reset the property:

   1: /// <summary>
   2: /// Sets the content types.
   3: /// </summary>
   4: /// <param name="web">The web.</param>
   5: /// <param name="list">The list.</param>
   6: /// <param name="contentTypesToAdd">The content types to add.</param>
   7: /// <param name="contentTypesToDelete">The content types to delete.</param>
   8: /// <param name="contentTypeOrder">The content type order.</param>
   9: public static void SetContentTypes(SPWeb web, SPList list, string[] contentTypesToAdd, string[] contentTypesToDelete, string[] contentTypeOrder)
  10: {
  11:     foreach (string ct in contentTypesToAdd)
  12:     {
  13:         AddContentTypeToList(web, list, ct.Trim());
  14:     }
  15:     foreach (string ct in contentTypesToDelete)
  16:     {
  17:         foreach (SPContentType contentType in list.ContentTypes)
  18:         {
  19:             if (contentType.Name.ToLowerInvariant() == ct.Trim().ToLowerInvariant())
  20:             {
  21:                 list.ContentTypes.Delete(contentType.Id);
  22:                 break;
  23:             }
  24:         }
  25:     }
  26:     ChangeContentTypeOrder(list, contentTypeOrder);
  27: }
  29: /// <summary>
  30: /// Changes the content type order.
  31: /// </summary>
  32: /// <param name="list">The list.</param>
  33: /// <param name="contentTypes">The content types.</param>
  34: public static void ChangeContentTypeOrder(SPList list, string[] contentTypes)
  35: {
  36:     if (contentTypes.Length == 0)
  37:         return;
  39:     IList<SPContentType> contentTypeOrder = new List<SPContentType>();
  40:     foreach (string contentTypeName in contentTypes)
  41:     {
  42:         SPContentType contentType = null;
  43:         try
  44:         {
  45:             contentType = list.ContentTypes[contentTypeName.Trim()];
  46:         }
  47:         catch (ArgumentException)
  48:         {
  49:             Log("WARNING: Unable to set content type order for '{0}'.  Content type was not found.",
  50:                 contentTypeName);
  51:         }
  52:         if (contentType != null)
  53:             contentTypeOrder.Add(contentType);
  54:         else
  55:             Log("WARNING: Unable to set content type order for '{0}'.  Content type was not found.",
  56:                 contentTypeName);
  57:     }
  58:     list.RootFolder.UniqueContentTypeOrder = contentTypeOrder;
  59:     list.RootFolder.Update();
  61: }
  64: /// <summary>
  65: /// Adds the content type to list.
  66: /// </summary>
  67: /// <param name="web">The web.</param>
  68: /// <param name="list">The list.</param>
  69: /// <param name="contentTypeName">Name of the content type.</param>
  70: /// <returns></returns>
  71: public static SPContentType AddContentTypeToList(SPWeb web, SPList list, string contentTypeName)
  72: {
  73:     SPContentType contentType = null;
  74:     try
  75:     {
  76:         contentType = list.ContentTypes[contentTypeName];
  77:     }
  78:     catch (ArgumentException)
  79:     { }
  80:     if (contentType == null)
  81:     {
  82:         try
  83:         {
  84:             // Get the content type from the web and add to the list.
  85:             contentType = web.ContentTypes[contentTypeName];
  86:         }
  87:         catch (ArgumentException)
  88:         {
  89:         }
  90:         if (contentType == null)
  91:             throw new SPException(string.Format("Unable to find content type '{0}'", contentTypeName));
  93:         return list.ContentTypes.Add(contentType);
  94:     }
  95:     return null;
  96: }

The help for the command is shown below:

C:\>stsadm -help gl-setlistcontenttypes

stsadm -o gl-setlistcontenttypes

Adds or removes content typews associated with the given list.

        -url <list view url>
        [-add <comma separated list of content type names to add to the list>]
        [-remove <comma separated list of content type names to remove from the list>]
        [-order <new button order, comma separated, first will be the default>]

The following table summarizes the command and its various parameters:

Command Name Availability Build Date
gl-setlistcontenttypes WSS v3, MOSS 2007 8/6/2008

Parameter Name Short Form Required Description Example Usage
url   Yes The URL to the list of which the actions will be performed -url http://portal/Lists/Events
add a No A comma separated list of content type names to add to the list.  It's recommended to wrap the value in quotes if more than one. -add "Holiday,Vacation,Company Event"

-a "Holiday,Vacation,Company Event"
remove r No A comma separated list of content type names to remove from the list.  It's recommended to wrap the value in quotes if more than one. -remove Event

-r Event
order   No A comma separated list of content type names.  Sets the order of the items in the "New" button of the list.  The first item will be the default content type. -order "Vacation,Holiday,Company Event"

The following is an example of how to set the content types for a list:

stsadm -o gl-setlistcontenttypes -url http://portal/Lists/Events -add "Holiday,Vacation,Company Events" -remove "Event" -order "Vacation,Holiday,Company Event"


Corey said...

Gary - first off, great, great blog. After using this command, I was disappointed to see that it does not turn on "allow management of content types". However, after digging into the OM using Powershell, I now see that the SPList.ContentTypesEnabled does not have a setter. That's unfortunate. Anyway, thanks for the great content!

Gary Lapointe said...

Corey - actually it does have a setter - I just added an "allowmanagement" parameter to the command so if you download the latest you should be able to set this property now.

Michal said...

could you let me know how you turned on the "allow managment of content types"? I can't seem to d\l and view the code.

Gary Lapointe said...

I guess I forgot to include that in my code snippet - it's real easy though - you just set the ContentTypesEnabled property of the SPList object to true.

Kanna said...

Thanks for this valuable post, I have a qeury is there a way to add description for "Email Distribution List" column on People and Group list of SharePoint.

This Column will be enabled while Incoming email is configured on the SharePoint farm.

Thanks in advance.

Gary Lapointe said...

Haven't tried but you should be able to edit that field to add a column - in the end it's just another field in a list.

tripwire said...

Hi Gary, me again, looking to you for another solution for my MOSS woes. :)

I have a content type on a document library that I cannot remove because it says it's in use. If it is, I can't see where.

I've been through every document and it's not set anywhere. I also emptied both recycle bins.

The content type doesn't even exist in the Content Type Gallery!

I don't suppose there's a way to force its removal??

Gary Lapointe said...

Look at the content type usages stuff I did (I believe in the powershell cmdlets). That should tell you where it's being used still. There's no way to force a deletion that I know of - you may have to just hide it if you can't find where it is being used.

tripwire said...

Thanks Gary. I know where it's being used I just can't get rid of the darn thing. Going to attempt migration tot anew library wihtout dependencies.

casy said...

Really great stuff!
Anyway to hide a CT in script?