Posted on:
Categories: SharePoint
Description:

While doing a SharePoint 2010 to 2013 upgrade you might run into situations where you would like to automate the upgrade process a bit.  I've worked with numerous SharePoint 2010 deployments that contain a number of customizations that will require a lot of manual work to switch everything over to 2013. 

For example, if you are dealing with a large Intranet that has a highly customized look and feel via branding (Master Pages, Page Layouts and Cascading Style Sheets), and then add in hundreds (or perhaps thousands) of pages that contain custom Web Parts spread over numerous site collections, you probably don't feel like manually switching everything over to their new SharePoint 2013 equivalents.  This is where some custom utilities could come in handy.

As you might know, SharePoint 2013 allows you to host SharePoint 2010 Site Collections without having to do much work besides a database attach to a Web Application and ensuring all the required custom solutions (WSP's) are deployed (that's definitely not all that's involved for a successful upgrade but it's enough for this overview).  So for upgrading your current farm to SharePoint 2013 it's not a huge undertaking if you are happy leaving your Site Collection(s) in SharePoint 2010 mode.  If you are looking to take advantage of all the newer features though, you'll want to eventually upgrade those Site Collections to 2013 mode.

I'm not going to go into too much detail here what the advantages/changes are of SharePoint 2013 over 2010, but some of the ones I was looking to leverage are:

  • Better branding implementation (ability to better leverage HTML5 and CSS3)
  • Channel Management (to better target mobile and tablets)
  • .Net 4.0 for Web Parts and other custom solutions

While I was in the process of updating all the custom solutions to SharePoint 2013, I ran into some minor issues when actually updating everything in the Site Collection.  When you upgrade a site collection you usually will just open up the SharePoint 2013 Management Shell and run the following cmdlet:

Upgrade-SPSite -ID http://siteurl -VersionUpgrade

This will start upgrading your Site Collection from 2010 to 2013 mode.  This is quite handy, but I was running into an issue about the order of doing things, and I wanted it more streamlined for this update.

When you upgrade your Site Collection to 2013 mode, SharePoint also will set all your default channel settings (these are stored in a file called __DeviceChannelMappings.aspx that is stored in the Master Page Gallery for your Site Collection.  There isn't much documentation on this file, but if you look at the source code of the file you'll see all the channel defaults are configured to the Master Pages and Alternate CSS settings you had when you performed the upgrade. 

I wanted to be able to automate the removal of the custom 2010 branding and apply the new 2013 branding all in one pass.  This would allow me to remove all the unused assets and other elements such as the custom Content Types for the publishing page layouts, unfortunately, due to the default channel mappings set up my code wasn't able to remove the old Master Pages because they were being referenced by the __DevinceChannelMappings.aspx file.  I could have gone in and manually configured the channel settings to the new Master Pages, and then deleted the files, but then I'd have to do this on every Site Collection (I know, I could write a couple different console applications to do each series of changes between all the manual configuration steps, but I prefer to get as much done in a single pass as possible).

To get around this, I decided it would be better to do the Site Collection upgrade in code while the branding changes were being applied.  This allowed for a single console application to:

  • Deactivate the old 2010 Branding
  • Upgrade the Site Collection to 2013 mode
  • Apply the new 2013 Branding
  • Switch all page layouts from the 2010 versions to the new 2013 versions
  • Remove all the 2010 branding assets and other related elements

So I attempted to use the SPSite.Upgrade() method that has been added in 2013, and then just monitor the upgrade status and site schema version to determine if the upgrade was completed (SPSite.SchemaVersion and SPSite.UpgradeInfo properties).  Unfortunately this didn't seem to do the trick.

From looking at the ULS logs, it appears that the SPSite.Upgrade() call was trying to upgrade the Site Collection to the target template version of 14.0.0.3, which it was already at, so no upgrade process was starting. 

So with the only roadblock still was upgrading the site collection to 2013 mode in my utility app I fell back on leveraging reflection to see if there was another way to do this. 

Note: Use this at your own risk because this isn't supported by Microsoft and things could change after a Cumulative Update.

So in the SPSite class I discovered a set of methods called StartUpgrade.  There was a few instances of that method with different signatures, but I used this one for my situation:

internal void StartUpgrade(SPSiteUpgradeType upgradeType, bool queueOnly)

So in your code you will want to include a reference to System.Reflection and then you could use the following method to do a synchronous upgrade on your Site Collection.

private static void UpgradeSiteCollection(SPSite site, Logger logger)
{
 if (site.SchemaVersion.Major < 15)
 {             
  var siteType = typeof (SPSite);

  Type[] paramTypes =
   {
    typeof (SPSiteUpgradeType),
    typeof (bool)
   };

  object[] parameters =
   {
    SPSiteUpgradeType.VersionUpgrade,
    false
   };

  var methodStartUpgrade = siteType.GetMethod("StartUpgrade",
            BindingFlags.NonPublic | BindingFlags.Instance,
            null, paramTypes, null);

  if (methodStartUpgrade != null)
  {
   methodStartUpgrade.Invoke(site, parameters);
  }
 }
}

As SharePoint 2013 continues to mature the documentation on the additions to the SharePoint Object Model should expand. Hopefully there'll be some documentation on how to properly do a Site Collection upgrade via the object model without having to rely on using a workaround like this.