Propagate Content Type Changes

Posted on Posted in SharePoint 2007, STSADM Commands

This is something that I put together a while ago but I’m only just now getting to the point where I can document it.  I was looking for a solution to a common problem of propagating changes to content types deployed via a Feature and I came across a post by Søren Nielsen.  Søren created a custom stsadm command which handles pushing down the content type changes.  I didn’t want to re-invent the wheel but I needed the ability to call the code in different ways and I wanted to try my hand at using the SPContentTypeUsages class so I decided to use what he created and just refactor it to meet my goals.  Søren does a great job at explaining the problem and what the code is doing so I won’t reiterate it here.  My modified version of the code can be seen below:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Collections.Specialized;
   4: using System.Diagnostics;
   5: using System.Text;
   6: using Lapointe.SharePoint.STSADM.Commands.OperationHelpers;
   7: using Lapointe.SharePoint.STSADM.Commands.SPValidators;
   8: using Microsoft.SharePoint;
   9:  
  10: namespace Lapointe.SharePoint.STSADM.Commands.ContentTypes
  11: {
  12:     /// <summary>
  13:     /// This code was derived from Søren Nielsen's code that he provides on his blog: 
  14:     /// http://soerennielsen.wordpress.com/2007/09/11/propagate-site-content-types-to-list-content-types/
  15:     /// </summary>
  16:     public class PropagateContentType : SPOperation
  17:     {
  18:         /// <summary>
  19:         /// Initializes a new instance of the <see cref="PropagateContentType"/> class.
  20:         /// </summary>
  21:         public PropagateContentType()
  22:         {
  23:             SPParamCollection parameters = new SPParamCollection();
  24:             parameters.Add(new SPParam("url", "url", true, null, new SPNonEmptyValidator()));
  25:             parameters.Add(new SPParam("contenttype", "ct", true, null, new SPNonEmptyValidator()));
  26:             parameters.Add(new SPParam("verbose", "v"));
  27:             parameters.Add(new SPParam("updatefields", "uf"));
  28:             parameters.Add(new SPParam("removefields", "rf"));
  29:  
  30:             StringBuilder sb = new StringBuilder();
  31:             sb.Append("\r\n\r\nPropagates a site scoped content type to list scoped instances of that content type.\r\n\r\nParameters:");
  32:             sb.Append("\r\n\t-url <site collection url>");
  33:             sb.Append("\r\n\t-contenttype <content type name>");
  34:             sb.Append("\r\n\t[-verbose]");
  35:             sb.Append("\r\n\t[-updatefields]");
  36:             sb.Append("\r\n\t[-removefields]");
  37:  
  38:             Init(parameters, sb.ToString());
  39:         }
  40:  
  41:         /// <summary>
  42:         /// Gets the help message.
  43:         /// </summary>
  44:         /// <param name="command">The command.</param>
  45:         /// <returns></returns>
  46:         public override string GetHelpMessage(string command)
  47:         {
  48:             return HelpMessage;
  49:         }
  50:  
  51:         /// <summary>
  52:         /// Runs the specified command.
  53:         /// </summary>
  54:         /// <param name="command">The command.</param>
  55:         /// <param name="keyValues">The key values.</param>
  56:         /// <param name="output">The output.</param>
  57:         /// <returns></returns>
  58:         public override int Execute(string command, StringDictionary keyValues, out string output)
  59:         {
  60:             output = string.Empty;
  61:             
  62:             using (SPSite site = new SPSite(Params["url"].Value.TrimEnd('/')))
  63:             {
  64:                 Process(site, Params["contenttype"].Value, Params["verbose"].UserTypedIn, Params["updatefields"].UserTypedIn,
  65:                     Params["removefields"].UserTypedIn);
  66:             }
  67:             return OUTPUT_SUCCESS;
  68:         }
  69:  
  70:         /// <summary>
  71:         /// Processes the content type.
  72:         /// </summary>
  73:         /// <param name="site">The site.</param>
  74:         /// <param name="contentTypeName">Name of the content type.</param>
  75:         /// <param name="verbose">if set to <c>true</c> [verbose].</param>
  76:         /// <param name="updateFields">if set to <c>true</c> [update fields].</param>
  77:         /// <param name="removeFields">if set to <c>true</c> [remove fields].</param>
  78:         public void Process(SPSite site, string contentTypeName, bool verbose, bool updateFields, bool removeFields)
  79:         {
  80:             Verbose = verbose;
  81:             try
  82:             {
  83:                 Log("Pushing content type changes to lists for '" + contentTypeName + "'");
  84:                 // get the site collection specified
  85:                 using (SPWeb rootWeb = site.RootWeb)
  86:                 {
  87:                     //Get the source site content type
  88:                     SPContentType sourceCT = rootWeb.AvailableContentTypes[contentTypeName];
  89:                     if (sourceCT == null)
  90:                     {
  91:                         throw new ArgumentException("Unable to find Content Type named \"" + contentTypeName + "\"");
  92:                     }
  93:  
  94:                     IList<SPContentTypeUsage> ctUsageList = SPContentTypeUsage.GetUsages(sourceCT);
  95:                     foreach (SPContentTypeUsage ctu in ctUsageList)
  96:                     {
  97:                         if (!ctu.IsUrlToList)
  98:                             continue;
  99:  
 100:                         using (SPWeb web = site.OpenWeb(ctu.Url))
 101:                         {
 102:  
 103:                             SPList list = web.GetList(ctu.Url);
 104:                             SPContentType listCT = list.ContentTypes[ctu.Id];
 105:                             ProcessContentType(list, sourceCT, listCT, updateFields, removeFields);
 106:                         }
 107:                     }
 108:                 }
 109:                 return;
 110:             }
 111:             catch (Exception ex)
 112:             {
 113:                 Log("Unhandled error occured: " + ex.Message, EventLogEntryType.Error);
 114:                 throw;
 115:             }
 116:             finally
 117:             {
 118:                 Log("Finished pushing content type changes to lists for '" + contentTypeName + "'");
 119:             }
 120:         }
 121:  
 122:         /// <summary>
 123:         /// Processes the content type.
 124:         /// </summary>
 125:         /// <param name="list">The list.</param>
 126:         /// <param name="sourceCT">The source CT.</param>
 127:         /// <param name="listCT">The list CT.</param>
 128:         /// <param name="updateFields">if set to <c>true</c> [update fields].</param>
 129:         /// <param name="removeFields">if set to <c>true</c> [remove fields].</param>
 130:         private static void ProcessContentType(SPList list, SPContentType sourceCT, SPContentType listCT, bool updateFields, bool removeFields)
 131:         {
 132:             if (listCT == null)
 133:                 return;
 134:  
 135:             Log("Processing content type on list:" + list);
 136:  
 137:             if (updateFields)
 138:             {
 139:                 UpdateListFields(list, listCT, sourceCT);
 140:             }
 141:  
 142:             //Find/add the fields to add
 143:             foreach (SPFieldLink sourceFieldLink in sourceCT.FieldLinks)
 144:             {
 145:                 if (!FieldExist(sourceCT, sourceFieldLink))
 146:                 {
 147:                     Log(
 148:                       "Failed to add field "
 149:                       + sourceFieldLink.DisplayName + " on list "
 150:                       + list.ParentWebUrl + "/" + list.Title
 151:                       + " field does not exist (in .Fields[]) on "
 152:                       + "source content type", EventLogEntryType.Warning);
 153:                 }
 154:                 else
 155:                 {
 156:                     if (!FieldExist(listCT, sourceFieldLink))
 157:                     {
 158:                         //Perform double update, just to be safe
 159:                         // (but slow)
 160:                         Log("Adding field \""
 161:                            + sourceFieldLink.DisplayName
 162:                            + "\" to contenttype on "
 163:                            + list.ParentWebUrl + "/" + list.Title,
 164:                              EventLogEntryType.Information);
 165:                         if (listCT.FieldLinks[sourceFieldLink.Id] != null)
 166:                         {
 167:                             listCT.FieldLinks.Delete(sourceFieldLink.Id);
 168:                             listCT.Update();
 169:                         }
 170:                         listCT.FieldLinks.Add(new SPFieldLink(sourceCT.Fields[sourceFieldLink.Id]));
 171:                         listCT.Update();
 172:                     }
 173:                 }
 174:             }
 175:  
 176:             if (removeFields)
 177:             {
 178:                 //Find the fields to delete
 179:                 //WARNING: this part of the code has not been
 180:                 // adequately tested (though what could go wrong?  … 🙂
 181:  
 182:                 //Copy collection to avoid modifying enumeration as we go through it
 183:                 List<SPFieldLink> listFieldLinks = new List<SPFieldLink>();
 184:                 foreach (SPFieldLink listFieldLink in listCT.FieldLinks)
 185:                 {
 186:                     listFieldLinks.Add(listFieldLink);
 187:                 }
 188:  
 189:                 foreach (SPFieldLink listFieldLink in listFieldLinks)
 190:                 {
 191:                     if (!FieldExist(sourceCT, listFieldLink))
 192:                     {
 193:                         Log("Removing field \""
 194:                            + listFieldLink.DisplayName
 195:                            + "\" from contenttype on :"
 196:                            + list.ParentWebUrl + "/"
 197:                            + list.Title, EventLogEntryType.Information);
 198:                         listCT.FieldLinks.Delete(listFieldLink.Id);
 199:                         listCT.Update();
 200:                     }
 201:                 }
 202:             }
 203:         }
 204:  
 205:         /// <summary>
 206:         /// Updates the fields of the list content type (listCT) with the
 207:         /// fields found on the source content type (courceCT).
 208:         /// </summary>
 209:         /// <param name="list">The list.</param>
 210:         /// <param name="listCT">The list CT.</param>
 211:         /// <param name="sourceCT">The source CT.</param>
 212:         private static void UpdateListFields(SPList list, SPContentType listCT, SPContentType sourceCT)
 213:         {
 214:             Log("Starting to update fields ", EventLogEntryType.Information);
 215:             foreach (SPFieldLink sourceFieldLink in sourceCT.FieldLinks)
 216:             {
 217:                 //has the field changed? If not, continue.
 218:                 if (listCT.FieldLinks[sourceFieldLink.Id] != null
 219:                      && listCT.FieldLinks[sourceFieldLink.Id].SchemaXml
 220:                         == sourceFieldLink.SchemaXml)
 221:                 {
 222:                     Log("Doing nothing to field \"" + sourceFieldLink.Name
 223:                         + "\" from contenttype on :" + list.ParentWebUrl + "/"
 224:                         + list.Title, EventLogEntryType.Information);
 225:                     continue;
 226:                 }
 227:                 if (!FieldExist(sourceCT, sourceFieldLink))
 228:                 {
 229:                     Log(
 230:                       "Doing nothing to field: " + sourceFieldLink.DisplayName
 231:                        + " on list " + list.ParentWebUrl
 232:                        + "/" + list.Title + " field does not exist (in .Fields[])"
 233:                        + " on source content type", EventLogEntryType.Information);
 234:                     continue;
 235:  
 236:                 }
 237:  
 238:                 if (listCT.FieldLinks[sourceFieldLink.Id] != null)
 239:                 {
 240:  
 241:                     Log("Deleting field \"" + sourceFieldLink.Name
 242:                         + "\" from contenttype on :" + list.ParentWebUrl + "/"
 243:                         + list.Title, EventLogEntryType.Information);
 244:  
 245:                     listCT.FieldLinks.Delete(sourceFieldLink.Id);
 246:                     listCT.Update();
 247:                 }
 248:  
 249:                 Log("Adding field \"" + sourceFieldLink.Name
 250:                     + "\" from contenttype on :" + list.ParentWebUrl
 251:                     + "/" + list.Title, EventLogEntryType.Information);
 252:  
 253:                 listCT.FieldLinks.Add(new SPFieldLink(sourceCT.Fields[sourceFieldLink.Id]));
 254:                 //Set displayname, not set by previous operation
 255:                 listCT.FieldLinks[sourceFieldLink.Id].DisplayName = sourceCT.FieldLinks[sourceFieldLink.Id].DisplayName;
 256:                 listCT.Update();
 257:                 Log("Done updating fields ");
 258:             }
 259:         }
 260:  
 261:         /// <summary>
 262:         /// Fields the exist.
 263:         /// </summary>
 264:         /// <param name="contentType">Type of the content.</param>
 265:         /// <param name="fieldLink">The field link.</param>
 266:         /// <returns></returns>
 267:         private static bool FieldExist(SPContentType contentType, SPFieldLink fieldLink)
 268:         {
 269:             try
 270:             {
 271:                 //will throw exception on missing fields
 272:                 return contentType.Fields[fieldLink.Id] != null;
 273:             }
 274:             catch (Exception)
 275:             {
 276:                 return false;
 277:             }
 278:         }
 279:     }
 280: }

 

By refactoring the code slightly I’m now able to use the code via the stsadm command, which I called gl-propagatecontenttype, or I can call the Process method via my Feature Receiver by just adding a reference to the assembly – this way I can push changes to content types down to the lists they are bound to when my Feature is re-activated.  Here’s the syntax of the command:

C:\>stsadm -help gl-propagatecontenttype

stsadm -o gl-propagatecontenttype


Propagates a site scoped content type to list scoped instances of that content type.

Parameters:
        -url <site collection url>
        -contenttype <content type name>
        [-verbose]
        [-updatefields]
        [-removefields]

 

I suggest you avoid the use of the -removefields parameter if possible – I left it there because I thought I might need it but it’s usually not a good thing to do something so destructive in batch like that (just make sure you at least test the change before going to production with it).

Again – props to Søren – I just retooled his code some.

55 thoughts on “Propagate Content Type Changes

  1. The -removefields argument will remove any fields from the list scoped content type that are not in the site scoped content type. The -updatefields argument will update any fields in the list scoped content type to make it match that of the corresponding site scoped content type.

  2. Hi,

    Very useful stuff – helped me complete my very basic feature receiver 🙂 Thankyou.

    just one detail – you dont update the description, hidden, version, or documenttemplate properties of the content types.

    Also there is one little Gotcha:
    SPContentTypeUsage.GetUsages(sourceCT); will return all uses of sourceCT including content types that inherit from sourceCT. You need to be careful to traverse content type heirarchy correctly. Not sure what the answer is at the moment still looking…..

    Sam

  3. Thanks Gary and of course Søren for this one. Your owed many saved hours from a lot of people for these extensions!

    Just a question Gary – if you wanted to update a feature defined content type content type, can you think of a good way to update the feature, the site content type and then the list content types? I can see this or Søren’s command will take care of the site–>list propogation but any ideas on forcing an update to the feature and then the subsuquent site and list CT’s? Thanks in advance

  4. Nick – can you elaborate on what you mean by updating the Feature? Are you just talking about re-activating it (which you can do with the stsadm activatefeature command by passing the force parameter)? I’m assuming you know that though are looking for something more different?

  5. Hi Gary,

    I am just a little mindful of MS’s words of caution “Do not, under any circumstances, update the content type definition file for a content type after you have installed and activated that content type.”. I figured forcing the update is good enough but could that ever cause any issues?

  6. Well, you definitely have to understand the implications of what changes you are making. The recommendation in that article is basically Microsoft’s way to avoid potential pitfalls. I think that if you test your deployments and you understand the nature of the changes you are making then you’re okay – if things don’t work out then you know it’s just test so you can always blow the changes away – typically though I tell my clients, after initial roll-out, make all your content type changes via the browser and then update your feature with those changes in case you need to rebuild the farm – it requires a good change control process but it’s definitely safer.

  7. I have figured out what I was missing in that conversation – nicely detailed in another one of Sørens posts.

    I don’t suppose you have a good command to covert from ‘virtual’ to ‘feature’ based CT definitions without directly modifying the DB? That idea makes me a little (lot) nervous

  8. Hi gary

    Just came across your post searching for some other content type stuff (very interested in the copy method) – and then you reference my old post! Cool 🙂

    Glad you could use it. It needed a bit of refactoring, good job.

  9. Søren – I tried posting to your blog to let you know that I’d snagged your code and incorporated into my commands but I kept getting errors trying to post a comment so I figured you’d eventually stumble upon it 🙂

  10. Hi,

    About the gl-propagatecontenttype and especially the -updatefields parameter:

    I have a deployed contenttype and fields as a feature and afterwards i change values of single choisefield to my xml and do following operations
    1) upgradesolution
    2) deactivatefeature -force …
    3) activatefeature -force …
    4) gl-propagatecontenttype -updatefields

    The result is that values for choisefield in sitecontenttype has changed, BUT values in list contenttypes has not.

    I guess the first if comparison in UpdateFields(..) is not catching the changes..

    thanks for the great tool!

    -hkossu

  11. I have a feature that creates three site columns and then tries to attach them to different content types that inherit from eachother using the FeatureReceiver.

    To clarify: I have to create the fields in code because they are lookupfields and cannot add them in CAML.. a different story.

    Linking the first field to the top content type (My Document) works fine but attempting to link the second field to a child content type (My Correspondence) fails.

    LinkFieldToContentType(SPContext.Current.Site.RootWeb, “My Document”, (SPField)lookupSecurityClearance);

    …so far so good!
    LinkFieldToContentType(SPContext.Current.Site.RootWeb, “My Correspondence”, (SPField)lookupDocumentType);

    … crash. The error:
    LinkFieldToContentType: My Correspondence / The object has been updated by another user since it was last fetched.

    Here is the linking code.

    public static void LinkFieldToContentType(SPWeb web, string contentType, SPField field)
    {
    try
    {
    SPContentType ct = web.ContentTypes[contentType];
    ct.FieldLinks.Add(new SPFieldLink(field));
    ct.Update(true);
    }
    catch (Exception ex)
    {
    AddErrorToWindowsEventLog(“LinkFieldToContentType:”+ex.Message, EventLogEntryType.Error);
    }

    }

    I just don’t understand why the error pops up or why .update(true) simply doesn’t work.
    If I use simply .Update() nothing creashes but inheritance doesn’t happen.

    Any suggestions?
    Thanks,

  12. Hi Gary,

    Great library. We use it a lot.

    I’m having issues with this command. I’ve added a field to a site collection content type (Interior Page) that is a calculated field:

    =IF([Article Date]=””,””,TEXT([Article Date],”dddd, dd MMMM yyyy”))

    When I run your command to propagate the changes, I get:

    PROGRESS: Adding field “FormattedArticleDate” to contenttype on /en-US/Archive/a
    boutUs/newsAndArticles/Pages
    Unhandled error occured: The formula refers to a column that does not exist. Check the formula for spelling mistakes or change the non-existing column to an existing column.
    Finished pushing content type changes to lists for ‘Interior Page’
    The formula refers to a column that does not exist. Check the formula for spell
    ing mistakes or change the non-existing column to an existing column.

    The error doesn’t make any sense. The Article Date field does exist (I can see it when I look at properties for a page).

    Any help would be greatly appreciated. Thanks.
    – Ed.

  13. Gary (and Søren!)… propagate ContentType is exactly what I was working on… thanks for posting your solution and custom stsadm commands. They are an absolute must and time saver! (*_*)

  14. Hi,

    Your command his really usefull.
    I notice that some modification are not handle by this command. For Example, I change a site column to be “Required”. After running the script, the configuration is not propagated.
    Is that normal ?
    Do you plan to implement this

    thx again

    MM

  15. @Merlin

    I thought this as well. Running the command without parameters doesn’t seem to do anything noticable at the list level.

    You need to add the -updatelists flag.

    This has worked so well that I’ve since scripted it and replaced what was an otherwise very expensive and very clunky solution.

    @Gary Do you ever grow tired being thanked for your incredible contributions? 🙂

  16. Not sure if anyone else is getting this, or if it’s just me.

    All my custom site columns are getting the internal name at the List Content Type level for all sub sites and collections.

    e.g. Document Category becomes Document_x0020_Category.

    I’m running the latest version of Lapointe.SharePoint.STSADM.Commands.wsp and have tested this several times with new document libraries.

    The root site is unaffected by this issue – only sub sites and collections.

    I’m running the command with the -updatefields and -verbose parameters.

    Looking at the output I can see some odd things occurring. The process seems to run multiple times on the same list – I’m assuming for each of the inherited content types?

    And in the case of the affected sub sites, the first iteration on a library seems to Delete and Add every column, including system and sealed fields.

    8<–log snip

    PROGRESS: Processing content type on list:/AboutUs/Docos
    PROGRESS: Starting to update fields
    PROGRESS: Deleting field “ContentType” from contenttype on :/AboutUs/Docos
    PROGRESS: Adding field “ContentType” from contenttype on :/AboutUs/Docos
    PROGRESS: Done updating fields
    PROGRESS: Deleting field “SelectFilename” from contenttype on :/AboutUs/Docos
    PROGRESS: Adding field “SelectFilename” from contenttype on :/AboutUs/Docos
    PROGRESS: Done updating fields
    PROGRESS: Deleting field “FileLeafRef” from contenttype on :/AboutUs/Docos
    PROGRESS: Adding field “FileLeafRef” from contenttype on :/AboutUs/Docos
    PROGRESS: Done updating fields
    PROGRESS: Deleting field “Created” from contenttype on :/AboutUs/Docos
    PROGRESS: Adding field “Created” from contenttype on :/AboutUs/Docos
    PROGRESS: Done updating fields

    –8< end

    Any help appreciated.

  17. @Gary: To clarify the above, the column ID is still the same and updates are still occurring.

    But the Name and not the DisplayName is being applied at the List Content Type level.

    i.e. From XML definition.

    DisplayName=”Document Type”
    Name=”Document_x0020_Type”

    Hope that helps.

  18. If it’s any help, it looks as though ln:255 isn’t taking effect.

    I only just upgraded your solution so, if this was a recent code change, then it’s possible I need to recycle the app pools?

  19. It looks like the column order is also being affected on the List Content Type. Couldn’t see anything in the code that was managing this.

    Additionally, I don’t suppose there’s also a method to update the document template? This doesn’t seem to be affected by this command.

  20. Odd – not sure why that’s happening. It should only be updating fields if the schemas are different for the field and for fields such as ContentType, Created, etc. they should really never be different. No idea why the display name is changing to the internal name either. Odd…

  21. Hi Gary, I trust your 2010 testign is going well.

    Just wanted to let you know that I deleted the site columns and content types and then re-added via feature across all site collections. The column renaming problem no longer ssmes to occur.

    I’m now desperately hoping that you might have the opprtunity to add paramters or code mods to
    optionally push down Document Template and also correct the column order.

    The latter occurs when an inherited CT has columnar differences and the parent CT is used with the command. Any column that differs from the parent (e.g. Title column is marked as Required) gets Deleted and then Added to the end.

    Alternately, an -ignoreChildren parameter would do the trick. I could then write a batch file to hit each CT in turn.

    Let me knw how much I owe you! I’m not kidding. 😀

  22. I think I have a fix for the column ordering and document template. I’ve pushed out my changes if you want to take a look – hopefully it works for you. Thanks again for all your feedback – it’s most appreciated!

  23. We have the same problem with the display name changing to the internal name. It only happens on one list that uses the content type though!
    Did you ever get to the bottom of that issue Gary?

  24. Hi Gary, you really are great. I’m going to start doing some serious testing now!

    My main issue still seems to be with CT inheritance. Did you come up with anything for this, or should I just run the command on all required content types in order of inheritance?

  25. Hi Gary, initial testing has been successful. Column ordering is restored and the document template field is pushed down.

    In all cases, any child CTs will inherit the column values and flags (e.g. required, read only, hidden) of the CT specified in the command. Similarly, the document template is overwritten.

    Running the command again on each affected child CT restore the correct values for the list CT. I have batched this process and it’s very quick to run.

    As a final feature request, do you think you could add -doctemplate as an optional flag??

    Again — thank you, thank you, thank you. You’ve saved me hours of laborious manual work and down-time to repair broken CTs across an ever-growing farm!

  26. tripwire – thanks for the testing feedback – Not sure that I’ll have time to address the inheritance issue as my focus right now is getting this stuff working on 2010 – I might be able to do something when I start migrating this command over but can’t promise anything (same with the doctemplate switch).

  27. Gary,
    The above solution is not propagating the readonly, ShowInNewForm,ShowInEditForm attribute changes made in the xml file. Do you have any idea how to achieve this?

  28. The API doesn’t expose those attributes in a way that allows me to edit them without using reflection. You’d basically need to use reflection to get the internal XML representation and edit that XML.

  29. Thanks Gary…Do you have any idea how to use reflection to achieve this..Can you point me some sample code so that I will get better idea.

  30. Hi Gary

    What’s the main difference between your utility above and using the contenttype.update(true) command , that updates that contenttype and all child references. Am I missing something?

    all the best

  31. It seems this command doesn’t push down ‘default values’

    I have a field declared in xml

    1

    The field is pushed down to all existing pages lists, but the default value is unfortunately not.

    /Lars

  32. Gary, I am using the command gl-propagatecontenttype to propagate changes to my content type in my site collection to all Pages libraries that currently utilize it. The only thing that I changed in my content type is a single line of text field with a new max length of 30 characters instead of 20 characters. When I run the command stsadm -o gl-propagatecontenttype -url http://sharepointdev -contenttype “Tab Page” -verbose -updatefields. Do you know why my new max length of 30 was not pushed down to my lists? I check the code and it looks like it should do that. Please let me know what your thoughts are here on this matter.

  33. thanks for a nice tool, it saved me some time. please can you give me guidance on how i can automate the running of this tool whenever an update is done on the content type. I am looking at powershell for help, but been new to powershell, i need some help. please can anyone help?. i have multiple content types to update. any help will be appreciated

    1. Your challenge will be determining when an update is done and thus when to run the tool; you have several options including using a timer job which references the assembly directly – otherwise a simple scheduled task that runs command periodically might suffice.

  34. Hello Gary, i found a problem with this tool whilst testing. in my organisation we have sharepoint foundation and have site definition which have content types registered on the subsites. when i run this tool, it fails,
    example Pushing content type changes to lists for ‘Local Attraction’
    Unhandled error occured.
    Finished pushing content type changes to lists for ‘Local Attraction’
    STSADM.EXE : Unable to find Content Type named “Local Attraction”
    any help to resolve this issue will be well appreciated.

    1. The way I built it the Content Types need to be at the root of the Site Collection – I’ve just not had time to revisit it and rework to allow them to be defined at lower levels.

      1. Gary,

        This is a great tool! I have a few questions.
        1. Have you had a chance to rework the code to allow content types defined in webs to update child lists and webs?
        2. Similar to Priya above I need to change the properties of content types; specifically the ShowInEditForm and ShowInNewForm properties. These properties appear to be Read Only requiring that the changes be made at the list instance. Do you know of a way around this?

        Thanks for all of you help and time saving contributions to the community.

  35. Hi Gary,
    I tried your stsadm command but for me it doent seem to work.. I am trying to reflect changes I made to the site columns to the list columns so that whenever I edit any existing document in an existing document librabry I should be able to see my updated list column.

  36. Hi Gary,

    Really thank you so much. I have a question here. I am using SP 2013 and I created a separate site collection for content type hub and using that site collection hub to push down to all the site collections. So, I created a custom solution to deploy all my content types. So, in this case all the my content types are in different site collection are in Read-only mode. I ran your script by making my content type not read-only. But I didn’t see the changes in my lists. Could you please provide me how it work in SP 2013?


    Thanks,
    Venkat

  37. Its nice post. However i learnt that if we edit content types in SharePoint Designer then it reflects changes immediately.

Leave a Reply

Your email address will not be published. Required fields are marked *

*