Reorder SharePoint list columns to match it's parent content type

I ran into an issue today. I have a site Content Type that defines several list fields and I have a specific order for those fields to be displayed. Today I added a new site column to this content type and I updated the order of my fields in the content type as usual. However, the lists that use this content type became all out of whack in regards to the order of the fields. I tried to update the order in the Content Type again and push down the changes, but never had any luck.

So, being a developer, I wrote up a simple console app that will iterate through my sites (about 40 webs) and find my particular list and content type and reset the order of the fields to match the parent content type.

There isn't anything fancy about this, but I thought I would share anyway.

Since it is a console app, just copy the executable and the app.config file to your SharePoint server. Update the app.config with your own values.

This is only an example script, as with any script you run in your environment, ensure that you heavily test it in a test environment before running in production!

using System;
using System.Collections;
using System.Configuration;
using System.IO;
using System.Linq;
using Microsoft.Office.Server.Utilities;
using Microsoft.SharePoint;

namespace ReorderMeetingFields
{
    class Program
    {
        /// <summary>
        /// Logs a message to a text file that is located in the same directory as this console app. If the file doesn't exist, it will be created.
        /// </summary>
        /// <param name="message">The message to log.</param>
        /// <param name="isError">Is this an error or a normal message that we want to log?</param>
        internal static void LogMessage(string message, bool isError)
        {
            var fileName = String.Format("ErrorLog {0}.txt", DateTime.Now.ToLongDateString());

            if (!isError) fileName = String.Format("SuccessLog {0}.txt", DateTime.Now.ToLongDateString());

            StreamWriter stream = File.AppendText(fileName);
            TextWriter writer = stream;
            writer.WriteLine("{0}", message);
            writer.Flush();
            stream.Close();

            Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            try
            {
                // Retrieve some configuration values from our App.config file
                var siteUrl = ConfigurationSettings.AppSettings["SiteCollectionUrl"].ToString();
                var contentTypeName = ConfigurationSettings.AppSettings["ContentTypeName"].ToString();
                var listName = ConfigurationSettings.AppSettings["ListName"].ToString();
                Console.WriteLine("Configuration retrieved.");

                // Open the site collection
                using (SPSite site = new SPSite(siteUrl))
                {
                    // Retrieve the parent content type
                    SPContentType siteCt = site.OpenWeb().ContentTypes[contentTypeName];
                    Console.WriteLine("Retrieved the {0} site content type.", contentTypeName);

                    // Collect the field order of the parent content type and save it to a string array
                    ArrayList siteFieldOrder = new ArrayList();

                    foreach (SPFieldLink link in siteCt.FieldLinks)
                    {
                        siteFieldOrder.Add(link.Name);
                    }

                    string[] fieldStringArray = (string[])siteFieldOrder.ToArray(typeof(string));

                    // Create an instance of the Content Iterator so we can run through all of our existing sites.
                    var webIterator = new ContentIterator("WebIterator");

                    webIterator.ProcessSite(site,
                        new ContentIterator.WebProcessor((SPWeb web) =>
                        {
                            // Try to retrieve our list.
                            SPList list = web.Lists.TryGetList(listName);

                            if (list != null && !web.IsRootWeb) // In my case I don't want this to run on the root web, remove this condition if this doesn't apply
                            {
                                var listCT = list.ContentTypes[contentTypeName];
                                listCT.FieldLinks.Reorder(fieldStringArray);
                                listCT.Update();

                                // Write a message to the log
                                var message = String.Format("Reordered the fields in the '{0}' list on the '{1}' site.", list.Title, web.Url);
                                Console.WriteLine(message);
                                LogMessage(message, false);
                            }
                        }),
                        new ContentIterator.WebProcessorErrorCallout((SPWeb web, Exception ex) =>
                        {
                            var message = String.Format("Error in '{0}': {1}", web.Title, ex.ToString());
                            LogMessage(message, true);
                            return false;
                        }));
                }

                Console.WriteLine("Finished");
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                LogMessage(ex.ToString(), true);
            }
        }
    }
}