Eric Shupps and Eric Alan Shupps with BinaryWave the BinaryWave Inc in BinaryWave Incorporated around SmartTrack beside SharePoint Monitoring through SharePoint alongside SharePoint Monitoring visiting @eshupps via eshupps near SharePoint performance and SharePoint management. The SharePoint cowboy eshupps BinaryWave and more on Operational Intelligence via Eric Alan Shupps SharePoint blog. SharePoint monitoring is a hot topic along with SharePoint Performance Measurement and SharePoint tips and tricks from Eric Shupps for SmartTrack.
Another Eric Shupps on Technology and Eric Shupps on SharePoint with a new SharePoint Post from Eric Shupps. New BinaryWave post through BinaryWave Inc. and with another SharePoint blog we get to Eric Alan Shupps Blog about SharePoint development. That's Eric Shupps - BinaryWave or Eric Alan Shupps Fort Worth Grapevine Texas Dallas of BinaryWave talking about BinaryWave Operational Intelligence at
the SharePoint Cowboy blog and on twitter as @eshupps. Of course SharePoint Administration is on topic for eshupps and another great post from Eric Shupps regarding BinaryWave SharePoint and SharePoint Maintenance.

The latest guidance from Microsoft suggests that the use of client-side API's is now the preferred technique for customizing the user interface in SharePoint 2013 and SharePoint Online. This is a distinct departure from the tried-and-true approach of using custom master pages to create a branded SharePoint experience. Naturally, this has stirred up quite a debate in the design-oriented segment of the SharePoint community - refer to this excellent blog post on the subject from Cathy Dew, get some additional thoughts from Heather Solomon, and see Chris O'Brien's developer-oriented take here. Leaving aside for a moment the pros and cons of this approach as it relates to branding, one thing is clear – UI customizations are being pushed quite forcefully back into the hands of developers. This is almost certainly not a good thing, as developers are notoriously poor designers, so it will be imperative that designers and programmers develop a close working relationship in order to ensure that customer requirements are met. Customers, for their part, must be prepared to pay an even higher "customization tax" than ever before, as significant changes will require both branding and development expertise on a single project, or leave aside all requirements for modifying the SharePoint UI (which, for many, will mean just giving up on SharePoint altogether).

To be clear, this doesn't mean that custom master pages are no longer supported (they are) or that branding is not important (it is) but rather that the pace of change in the cloud product makes the maintenance of custom master pages much more difficult. Remember, SharePoint online is a service not a product – as such it is subject to a much faster update cycle than the on-premise version. To be perfectly frank, if you want complete control over the SharePoint interface, then go with the on-premise product. Your customizations will last longer, breaking changes will be far less frequent and the only time you'll have to pay the customization "tax" is during the next upgrade cycle. And no, that doesn't mean you will be stuck with maintaining all those pesky SharePoint servers yourself – there are plenty of vendors willing and able to take that task on for you. But it does mean you will give up online-specific features like Delve in favor of a branded Intranet; whether or not that's worth the trade-off is a decision each customer will have to make on their own. Based on my experience many customers want both the flexibility of the cloud and the ability to implement some level of interface customizations, which is certainly achievable – within certain limits.

Which leads me to the point of this post - if you decide you want to be in the cloud (or be "cloud ready") but still want some interface customizations, then read on, as there is one big "gotcha" that you absolutely must know about before you move forward.

The technique Microsoft is now recommending for customizations is known as "JavaScript Injection". Simply put, this means pushing client script into a page through the manipulation of existing elements, much as you can do with compiled code and Delegate Controls in an on-premise, full-trust environment. Leveraging the power of client-side frameworks such as jQuery, this technique allows designers to hide, remove, replace, or insert DOM objects as they see fit. There is a good example of this technique in the JavaScript Injection Sample on the Office Developer Patterns and Practices GitHub site. In the sample description, the designer wishes to hide the "new subsite" link on the Site Contents page, which can be accomplished by adding the following JavaScript into the site master page:

$("#createnewsite").parent().hide();

In order to "inject" the code programmatically the developer must leverage the Custom Actions functionality of SharePoint within an App. This is the same set of API's that permit the addition of custom buttons and links to the Ribbon, Menus and Edit Control Block (for more on how to create custom actions refer to the following MSDN Article: https://msdn.microsoft.com/en-us/library/office/jj163954(v=office.15).aspx). There is an existing location identifier in the Custom Action framework named "ScriptLink". It is accessible via the UserCustomActions collection on the parent SPWeb object. By adding a new custom action to the UserCustomActions collection and targeting the ScriptLink element, the code is then inserted into all pages on the site which contain the target element. This can be achieved using the following CSOM code (from the same JavaScript Injection Sample on GitHub referenced above):

This is where things start to get interesting. Take note of the fact that the above code is CSOM in a Provider Hosted App – this is a very important point we will be returning to shortly. For the moment, bear in mind that any script inserted programmatically must also be removed programmatically. The following code will reverse the insertion action by removing the script from the UserCustomActions collection:

public void DeleteJsLink(ClientContext ctx, Web web)

{

var existingActions = web.UserCustomActions;

ctx.Load(existingActions);

ctx.ExecuteQuery();

var actions = existingActions.ToArray();

foreach (var action in actions)

{

if (action.Description == "scenario1" &&

action.Location == "ScriptLink")

{

action.DeleteObject();

ctx.ExecuteQuery();

}

}

}

It is now time to discuss the "big gotcha" I referenced at the beginning. It stands to reason that if code is injected when an app is added to a site then that same code should be removed when the app is removed. This is an essential element in maintaining a healthy relationship between the developer and the site administrator. If the code is not removed gracefully then it will become orphaned with no way to remove it other than via more code. So the developer must take into account how the functionality they introduced will be retracted when it is no longer required or must be replaced by newer code. There is a very easy way to make sure this happens without requiring any additional effort – use a declarative element to insert the custom action instead of doing it programmatically. The functionality certainly exists within the app model – that's how Ribbon customizations are performed. Here is an example of how to achieve the same result using a CustomAction element within an App project:

<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<CustomAction

Location="ScriptLink"

ScriptBlock="$("#createnewsite").parent().hide();"

Sequence="100" />

</Elements>

Easy, isn't it? The best part is that declarative elements are automatically removed when the app is removed – no need for code to handle the removal process. So the obvious answer is to deploy a declarative instead of a programmatic custom action, right?

Not so fast.

Try doing this via an App and you will get – nothing. No errors, no deployment failure, no feedback whatsoever. The script is simply never added to the page. This is due to the fact that the parser specifically blocks SharePoint Apps from deploying declarative custom actions containing the "ScriptLink" value for the Location element. So the built-in mechanism for automatically handling the retraction of deployed artifacts is intentionally blocked in an App scenario.

Great. So what now?

Well, if the App in question is a Provider Hosted App, then - in theory - a remote event receiver could be used to call a method that is responsible for deleting the CustomAction element from the host web user actions collection when the app is removed. A remote event receiver is simply a WCF service with an endpoint the App can call in response to an AppInstalled or AppUninstalling event (an example of remote event receivers can be found in the Core.EventReceiversBasedModifications sample). Assuming the service can establish context with the host web and execute the requisite CSOM code then we would have an automated method for script retraction. But wait – is this really a viable solution? Be sure to read the "Dealing with Uninstall" section of the ReadMe page in the sample. It clearly points out that removing an app from the Site Contents page may not fire the AppUninstalling event or may do so with inadequate permissions. So there is no guarantee that a remote event receiver will solve the retraction problem.

Unfortunately, the story only gets worse from here. If the App in question is SharePoint Hosted then there are no options for automatic removal of injected scripts. None. The developer must provide a manual removal method and hope that the site administrator remembers to use it BEFORE removing the app. You read that right – any CustomActions created programmatically in a SharePoint Hosted App cannot be removed except by explicit execution of code. With no ability to add interaction to the app tile in Site Contents there is absolutely no way to notify the user removing an app that additional steps must be taken for graceful removal. The deployed code will remain resident in the master page until additional code is run to remove it.

SharePoint Hosted Apps have many advantages – they are easy to deploy, require no infrastructure on the part of the developer, eliminate the need to write code for establishing and managing context, automatically get provisioned in an app web, and have an integrated navigation experience. The second point is perhaps the most important – developers don't need to stand up a separate web site just to deploy their app. Sure, spinning up web sites in cloud services is easy and relatively cheap, but it still costs money, especially if a lot of people are hitting it, and not every developer has access to Azure, AWS or Google. As anyone who has ever worked on Enterprise development team can attest it is extremely difficult to get even a simple web site provisioned. Not to mention the hassle and headache of getting S2S trusts set up in on-premise scenarios or opening ports in the firewall for inbound connections for mobile/remote users. SharePoint Hosted Apps are a perfect solution in these scenarios yet they cannot be used for JavaScript injection because there is no mechanism for code retraction.

So where does this leave us in attempting to manage script injection in a responsible manner? Nowhere good, I'm afraid. Declarative actions cannot be used at all because their deployment is blocked. Provider Hosted Apps have an event automation mechanism but it is limited and unreliable. SharePoint Hosted apps have no automation options at all, instead requiring manual code execution without the ability to notify the user. Not to mention the fact that deploying custom actions in both SharePoint and Provider Hosted Apps requires Full Control permissions – a requirement not likely to get past Information Security and explicitly disallowed in apps published to the Office Store. And yet, despite the complete inability to effectively manage the deployment and retraction process, the script injection method via the app model is THE method being promoted by Microsoft for UI customizations in SharePoint 2013 and especially SharePoint Online.

Lest you suffer from the false impression that this is only a customization problem, allow me to correct that misconception. What about developers who rely upon script libraries like jQuery and its multitude of plugins to be present on every page in a site? How about custom style sheets, font libraries, navigation menus, and legal disclaimers? What happens if, for example, you need to invoke a full-page lightbox overlay from an app part? Or pass parameters from an app web page to a host web page via the postMessage API? All of these require script injection and the more of them you have the more orphaned code there will be lurking in the markup of every page.

Is that a big enough "gotcha" to get your attention? I sure hope so. Because if you follow the advice and samples currently being published you will eventually end up with orphaned code in your site(s).

And now for the coup de grâce.

At present, the only viable solution for elegantly managing script injection in all scenarios is…

…are you ready for it?

Sandbox Solutions.

Only script injection performed via a declarative sandbox solution is guaranteed to a) get past the parser in both on-premise and online scenarios, and b) get removed when the solution is deactivated. How is that for coming full circle? The very model for code isolation that was hyped in 2010, then quickly set aside to be replaced by the even more hyped up Cloud App Model in 2013, is the only solution that fully supports the "new" injection method. Of course, Sandbox Solutions come with their own raft of limitations and are considered to be "deprecated" so their use is no longer encouraged. But if you must inject JavaScript into pages in SharePoint then the sandbox is the only safe and reliable method for doing so.

Welcome to the new model. Same as the old model. Only it's new! And in the cloud!!!

​It's back! SharePoint Saturday 2015 will be held at the Microsoft campus in Las Colinas on March 7th. As always, the event is free for attendees and we will have a full roster of deep-dive sessions from MVP's, Microsoft personnel, community members and other subject matter experts. It will be full day of education education and networking covering a wide range of SharePoint and Office 365 topics. Reserve the date now and don't miss out!

Many organizations have a governance policy in which certain individuals are granted Full Control permissions of individual sites, usually after completing some training or demonstrating proficiency in site administration skills. In such a scenario, it is quite common for a number of different users to be site owners throughout a wide or deep site hierarchy without having any permissions beyond the sites the administer or to the parent site collection(s); in fact, they may not be any more than a common Visitor in the root site collection even though they are in the Owners group of their own site(s).

While this is an effective strategy for delegating site administration and support duties to non-IT personnel it can sometimes lead to unexpected permissions issues. Case in point: activating the SharePoint Server Publishing feature on a site. This feature, which provisions the various artifacts required for publishing and enables various publishing-related settings, is dependent upon a site collection scoped feature called "SharePoint Server Publishing Infrastructure". Site owners without administrative site collection permissions must first request activation of the dependent feature by the site collection owner before attempting to activate the publishing feature on their own site. In theory, this should be sufficient but unfortunately, activiation of the dependent feature is not enough to enable publishing on a child site - the site owner must also have a minimum set of permissions on at the site collection level.

If you have ever encountered this situation, then you have likely recieved the standard "Sorry, you don't have access to this page" screen when attempting to activate the publishing feature. This error can be misleading, as attempting to activate a feature doesn't have anything to do with trying to navigate to a page, but the underlying cause is the same - a System.UnauthorizedAccessException error is being thrown and the custom errors mode parser always redirects to the /_layouts/15/AccessDenied.aspx page if the "Allow access requests" option is checked under Access Requests Settings. The ULS log entry for this would look something like the following:

Event log message was: 'Failed to initialize some site properties for Web

There are numerous posts on the Internet which indicate that the solution to this problem is to give the user attempting to activate the feature at least "Read" permissions to the "DeviceChannels" list in the parent site collection. This is due to the fact that DeviceChannels, along with several of the other publishing-related lists such as "PublishedLinks" and "ReusableContent", have permission inheritance broken when they are created and the user in question won't have the ability to even read these lists. While activiation of the site-level publishing feature does, in fact, read from the DeviceChannels list, applying permissions only to this list may be insufficient. Testing on 2010 RTM/SP1/SP2 and 2013 RTM has shown that the site owner must also have "Member" rights plus the following site permissions on the root site collection in order to activate the publishing feature:

Add and Customize Pages - Add, change, or delete HTML pages or Web Part Pages, and edit the Web site using a Microsoft SharePoint Foundation-compatible editor.

Apply Themes and Borders - Apply a theme or borders to the entire Web site.

Apply Style Sheets - Apply a style sheet (.CSS file) to the Web site.

Esssentially, this is the same permission set as the "Designer" role with a few exceptions, such as "Use Self-Service Site Creation", "Browse User Information", etc. If assigning site owners full Design permissions is considered too permissive for your environment, you can create a custom permission level and group, then assign site owners to that group. Unfortunately, this means the site owners will also have rights to modify styles, master pages, and so on at the site collection root, which will probably not comply with the governance policy in most organizations. Other alternatives are to handle feature activiation via a PowerShell script or custom code. Alternatively, the site collection administrator could create a site template that already has the SharePoint Server Publishing feature activated and use that template for the creation of subsites as the design permissions are only required when activating the feature not for using the publishing components after it has been activated. Temporary assignment of these permission is also a potential workaround but it requires active participation by the site collection administrator. If you are using an advanced workflow solution like Nintex or K2 you might also be able to automate the process using an app step or elevated permissions within a workflow.

It's strange how things in your career come together over time. Way back in 2008 I was attending TechEd in Orlando, Florida (as documented here). We had a booth the first week to lauch our Sonar product (which eventually became part of SharePoint Diagnostic Manager​) and I was lurking about the Office kiosks the second week answering SharePoint development questions when I got roped into something called Speaker Idol. It was a fun little competition in which speakers are given five minutes to do a presentation to a panel of judges and a small audience. The winner of each heat went on to the finals with the prize being a speaking slot at the next TechEd. By pure luck I managed to win the competition and along the way met some really great people - the irrepressible Rachel Appel, the eloquent Alan Stevens, and the brilliant Amanda Leigh, to name just a few. But perhaps the best connections to come out of that event were with Richard Campbell and Carl Franklin, a dynamic duo who have brought us such great technical community resources as .NET Rocks, RunAs Radio, and The Tablet Show, not to mention speaking, producing, traveling cross-country on insane road trips and, oh yeah, making some killer music.

Richard and I have gotten together a few times over the years, both virtually and in person, to chat about various techincal topics - usually SharePoint - and I'm always amazed how much he knows about the technology industry in general and especially about our little corner of it. You would think his mind is already overflowing with general tech-related buzz but somehow he keeps his finger on the pulse of the SharePoint world as well. I really don't think he sleeps. Like, ever. I had another opportunity to chat with Richard recently on the topic of SharePoint search (and SharePoint/Office365/Azure/Cloud stuff in general) for RunAs Radio. I always enjoy our conversations and we never seem to have enough time to talk about everything on our minds. In any event, have a listen if you are so inclined and be sure to check out all the other things Richard is involved in. It's quality stuff!

One of the most common requirements in any SharePoint environment is the aggregation and summarization of content across lists, libraries, sites and site collections. Administrators could not easily achieve these requirements without custom code until the introduction of the Content Query Web Part (CQWP) in SharePoint 2007/2010. The CQWP gave administrators a useful out-of-the-box method for collecting data from various lists into a consolidated view. Even better, it could aggregate data from different sites – something the built-in List View Web Parts could never do. But, the CQWP certainly has its limitations – the number of sites it can query is limited, modifying the display requires expert XSL transformation skills, and the behind-the-scenes heavy lifting required to execute its queries can place a significant load on the infrastructure, especially when used on heavily trafficked pages...

This past weekend hundreds of SharePointers descended upon the wilds of Branson, Missouri for SharePointalooza. Despite being in the exact center of absolutely nothing we sill managed to have a good time, deliver some SharePoint knowledge, and listen to some great music. This was a labor of love and devotion to the community by Mark Rackley (supported by his long-suffering family) and he did an excellent job pulling everything together.

A big Texas "Thanks, y'all!" from myself and Miguel Wood to all those who attented our SharePoint 2013 High Availability workshop. Below are links to the slides and the demo script for configuring WSFC and SQL AlwaysOn Availability Groups.

P.S. - A special shout-out to Eric Harlan and Naomi Moneypenny for acting as co-pilots on our epic road trip to the Middle of Nowhere. They never panicked as they were drug through the backwoods of Oklahoma and Arkansas. They even managed to stay awake through all my stories which is an epic feat of endurance. Good times with good friends makes it all worthwhile.

If you have managed to successfully configure User Profile Synchronization in your 2013 environment (which is a daunting task in and of itself) then at some point you are going to have to deal with the personal sites of users who have been disabled or removed from Active Directory. SharePoint tries to be helpful in this regard by identifying account status changes during the synchronization process, deleting user profiles from the database, and notifying the user's manager (if there is one) of the fact that the associated My Site will be deleted in a couple of weeks. Unfortunately, this notification leads to a bit of confusion as the manager can't actually browse to the user's My Site from the provided link. Here's a sample of the system-generated email notification:

The My Site of [USERNAME] is scheduled for deletion in 14 days. As their manager you are now the temporary owner of their site. This temporary ownership gives you access to the site to copy any business-related information you might need. To access the site use this URL: https://[MY SITEHOST]/personal/[USERID]

The above email is generated when the My Site Cleanup Job timer job runs, at which time the user's manager is also added to the Site Collection Administrators group of the target My Site. Trouble is, the link itself doesn't work – browsing to it invokes the PersonalSpaceRedirect control on the default.aspx page for the SPSPERS site template, which checks to see if the current user is the site owner; if not, it redirects to the "person.aspx" page on the My Site host. Note that it specifically checks the site owner and secondary contact properties – it does not check to see what groups the user is a member of. So even though the manager has been given full control of the site collection they still get redirected to person.aspx whenever they try to browse to the My Site default home page.

This would be fine, as the standard links on the redirection page allow for navigation to the deleted user's OneDrive folder and from there to Site Settings and Site Contents, except for one major problem – as soon as person.aspx loads it errors out and the manager gets the ever-so-friendly "An error has occurred" page. For once, the error actually says what the problem is: "User not found". Why? Because the user's profile has already been removed from the profile database during the synchronization process. The page is dynamic, attempting to load the user information from the account name passed in the query string argument, but since there is no such user to be found anymore it throws an error.

The good news is that the original user's My Site is actually still there (well, it's there for 14 days, anyway – after that it's gone). If you know the SharePoint URL structure you can still browse to various system pages like "/_layouts/settings.aspx" and "/_layouts/viewlsts.aspx", as well as certain lists, including "/documents" (the user's OneDrive folder). This is fortunate, as user's don't have the ability to delete the core Documents folder, so if the manager knows the ropes they can just append "/documents" to the end of the link in the email and they're good to go. But not everyone knows this so it would be helpful if the link could be changed to point to the Documents folder instead of the home page but it cannot – there's no supported way (that I've been able to find) to modify the notification email. And this functionality remains broken even after SP1 and the June 2014 CU for SharePoint 2013 (seriously, who tests this stuff – anyone at all?).

So what can we do? Well, if you're up for it, you can write your own My Site cleanup timer job as Kirk Evans describes in this blog post (which is also good reading for background on the entire synchronization and cleanup process). If you want to modify the length of time before a deleted user's My Site is removed, change the email text, or otherwise make changes to the overall process then this is your only option. But what if you just want to address the broken person.aspx redirect problem? Unfortunately, you still need some custom code, but there is a way to do it that's not quite as painful as writing a custom timer job. I'll walk you through a quick solution that I came up with – there are probably a dozen other ways to do this but it solves the problem in a supported way with minimal code to maintain.

At the root of the problem is the PersonalSpaceRedirect control. You can find the control reference by opening the C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\SiteTemplates\SPSPERS\default.aspx file on any SharePoint web server (NOTE: Please don't modify this file directly – that's unsupported and a bad practice in general). Below all the control registrations and page directives you'll find this bit of markup:

As mentioned above, this control handles redirection for users who aren't the site owner of a given My Site by checking the site owner and secondary contact properties, and if the user is neither of those then it sends them to the person.aspx page instead (if you'd like to investigate it yourself you can find it in the Microsoft.SharePoint.Portal.WebControls assembly using ILSpy or Reflector). Naturally, the My Site Cleanup Job doesn't make the manager a site owner or secondary contact, it simply adds them to the Site Collection Administrators group. Although the control itself is public several of the dependent methods are not so extending the control with a custom implementation that works properly isn't feasible and completely replacing it with a custom Site Definition is a lot more trouble than it's worth. Instead, we can preempt the behavior of this control by adding a custom redirection control of our own to the page using the delegate control mechanism of SharePoint.

If you've never worked with delegate controls before the underlying principle is simple: they are server controls which get "stapled" to a parent control to provide a method for injecting code into each page in a site, site collection, web application or farm (depending upon how they are scoped). By selecting one of the out of the box controls in the default master pages (or a customized master page with similar markup) that accepts multiple child controls we can add our own logic to the page at runtime. Using this method we can write our own redirection control which checks the group membership of the current user and, if they are a site collection administrator but not a site owner or secondary contact, redirect them to a page which doesn't have the PersonalSpaceRedirect control – like the default OneDrive "Documents" library.

[NOTE: Delegate controls are full-trust code and therefore not compatible with the SharePoint 2013 App Model or Office 365]

Creating a delegate control is pretty simple (refer to this link for a step-by-step walkthrough). Create a new empty SharePoint project in Visual Studio 2013 using the "Full Trust" option and add a new class. Then override the OnInit event with the code you want to run or a method reference (I prefer using method references whenever possible for testability purposes):

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using Microsoft.SharePoint;

using Microsoft.SharePoint.Administration;

using Microsoft.SharePoint.Utilities;

using Microsoft.SharePoint.Security;

using Microsoft.SharePoint.WebControls;

namespace BinaryWave.SP.My Site

{

public class PageRedirector : WebControl

{

protected override void OnInit(EventArgs e)

{

RedirectUser();

base.OnInit(e);

}

}

}

Next, add a new method with logic to check the user's group membership and redirect them to the "Documents" library.

protected void RedirectUser()

{

try

{

SPWeb web = SPContext.Current.Web;

if (web.WebTemplate == "SPSPERS")

{

SPSite site = web.Site;

SPUser user = web.CurrentUser;

string targetUrl = web.Url + "/Documents";

string welcomeUrl = web.RootFolder.WelcomePage;

if (web.UserIsSiteAdmin || site.UserIsSiteAdminInSystem)

{

if (site.Owner.LoginName.ToLower() != user.LoginName.ToLower())

{

if (HttpContext.Current.Request.Url.AbsoluteUri.Contains("default.aspx"))

HttpContext.Current.Response.Redirect(targetUrl, true);

}

}

}

}

catch (System.Exception ex)

{

//Log to

}

}

You can then add an empty SharePoint element to the project and edit the Elements.xml file to specify which control on the page your new delegate control will be stapled to. I chose "AdditionalPageHead" as it normally can be found at the top of a default master page (if you are using a custom master page you may need to alter the control reference). Note that you will need the full assembly name and public key token values for your project – you can get these by compiling the project and using the Strong Name Tool in Visual Studio.

A Feature will have already been created in the project once the empty element was added –edit this Feature to change the name, description, etc. If you have chosen to configure your My Site Host as a separate web application then the Feature should be scoped to "Web Application" and deployed to that specific web application. If your My Site host is in the same web application as your primary content then you may want to add some additional code to prevent the control from executing its payload one very single site in the web application; likewise, if you are using a custom web template or site definition then you'll want to change the reference to "SPSPERS" in the redirection method.

Remember to add Safe Control entries for the project component which contains your Elements.xml file (from the Properties panel, expand the Safe Control Entries collection and Add a new entry with the proper settings) then add the solution to SharePoint and deploy it to the target web application. You can test it by adding a user to the Site Collection Administrators group for a My Site then attempting to load the My Site home page – the control should kick in and redirect you to that user's "Documents" library. There are probably a number of variations on this approach that would enhance the functionality but this is a quick and simple way to solve the "User not found" issue with Person.aspx.

The full source code for this solution is available here (requires Visual Studio 2013). If you just want the farm solution for deployment in your environment the WSP file can be downloaded separately. If you choose the latter option, please test it in a development farm first as your configuration might be different.

Anyone who has ever tried to do an in-place upgrade from SharePoint 2007 to 2010 knows what a complete nightmare that process could be; without much effort you could easily destroy a farm and spend endless hours trying to rebuild from scratch. The process was so fragile and prone to failure that in the 2013 release Microsoft removed the option altogether, allowing only content database detach and re-attach migrations. This greatly improved the chances of success and is, for the most part, a pretty seamless operation for the majority of deployments. But every now and then you come across a strange configuration that throws a spanner into the works and turns a simple migration into a huge headache.

Case in point. I recently received a distress call from a user who was trying to migrate a single content database from 2010 to 2013 and getting all sorts of strange results. Although the migration appeared to succeed, all the content was over a year old – documents, sites, list items, customizations – everything was out of date. Initially, it was thought that a second database had been mounted at some point during the preceding year but that wasn't the case – trolling through the SQL server backups it was obvious that there was only ever one database for that web application. Since database corruption is always a possibility, they tried restoring and mounting successive backups going back several months but nothing changed – the old data kept showing up. Running out of time in the assigned maintenance window, the administrator then tried restoring the original database back to 2010 and the same thing happened – old content showed up and the new stuff had simply vanished. Now they really had a problem as both environments, the original 2010 farm and the new 2013 farm, were completely unusable.

Curious as to what might have gone sideways, I had them check the AllDocs and AllLists tables in a copy of the current content database for the latest TimeLastModified value to see if it matched up with the results in the user interface (NOTE: This was an offline copy and not a production database – you should never go poking around in production SharePoint databases). That's when we got a real shock. The database actually contained current lists, documents and list items! Although we couldn't see them when viewing Site Contents, there they were plain as day in the database, with the proper metadata values and template associations. And they weren't hidden, either – attempts to get at them programmatically also failed. Something really weird was going on.

After replicating the steps they took a few times on my own, and getting the same results, I decided to have a look at the upgrade log files. Turns out that even though no errors were displayed during the mount operation there were actually a small number of errors encountered during the upgrade process. The first one I came across made it seem as if whole site collections were missing:

07/20/2014 15:49:45.68 powershell (0x0EAC) 0x20C8 SharePoint Foundation Upgrade SPContentDatabaseSequence ajxkz ERROR Database [WSS_Content] contains a site (Id = [aa3fd23b-5c67-4996-a7c6-773d450945d8], Url = [/sites/abc]) that is not found in the site map. Consider detach and reattach the database.

Well that was obviously nonsense as I knew for a fact that the site collection did exist – I could navigate to it after the upgrade completed. It was followed by a warning indicating that "orphaned sites could cause upgrade failures". Um, yeah, I suppose they would, except there were no orphans in this case – the site really did exist. And then a few lines later I found this little gem:

07/20/2014 15:49:45.68 powershell (0x0EAC) 0x20C8 SharePoint Foundation Upgrade SPContentDatabaseSequence ajxk3 ERROR Database [WSS_Content] contains a site (Id = [aa3fd23b-5c67-4996-a7c6-773d450945d8], Url = [/sites/abc]) whose url is already used by a different site, in database (Id = [973995d8-d187-42c3-890e-04031a48811e], name = [WSS_Content]), in the same web application. Consider deleting one of the sites which have conflicting urls.

Huh? How could two site collections have the same URL? Surely that was nonsense also but just to be sure I ran a quick query against the AllSites table – and stared in disbelief at the results. There were five rows in the table when there should only have been three (that's how many site collections showed up in Central Administration for that web application both before and after the upgrade process). Where did the extra rows come from and what sites did they refer to? Well, as it turned out, they referred to the exact same site collections but with an earlier TimeCreated value. Somehow, site collections had been created, then later re-created with the same URL's, without the old ones being removed from the database. The upgrade operation was obviously using the earlier values when it updated the schema and object associations, which explained why objects existed in the database tables that weren't exposed in the UI – it was just ignoring references to site GUID's that didn't match the two it selected. A quick look back at the AllLists table confirmed it, as tp_SiteId did in fact refer to the earlier site collections.

Now that I knew what was happening, the fix was easy. First, I removed the existing site collections which were based on the old instances, using the Remove-SPSite command. I then dismounted the database and mounted it again. This time, with the old site references gone from the AllSites table, the proper site associations were made and the correct content, including all the lists, libraries, documents and items, was restored. Problem solved. The only remaining mystery was how additional site collections were created with the same URL as ones that were already in the database – this shouldn't be allowed to happen. I still don't have an answer for that but at least the customer was able to carry on with their migration without suffering any data loss. I'll put that one in the "win" column.

PremierPoint Solutions (formerly SharePoint Solutions) has recently released an updated version of their Site Provisioning and Governance Assistant product for on-premise deployments of SharePoint 2010 and 2013. SPGA is designed to address a common concern in enterprise SharePoint deployments – administrative control over site growth and proliferation. Anyone who has ever tried to contain the spread of SharePoint in a manageable and consistent way will appreciate how difficult it can be to enforce governance while at the same time allowing users to use the platform to its full potential.

I was fortunate to have a chance to work with the PremierPoint team to bring the new release of SPGA to market. In conjunction with their Extranet Configuration Manager product, SPGA provides administrators with the ability to define a wide range of rules surrounding the site creation process that support governance policies and objectives. Beyond simple workflows and item-level approvals, SPGA provides a toolbox for implementing flexible and repeatable processes for just about any scenario. This latest release includes some new features and functionality but the real news is that there is now a completely free version. You can download and install it on any SharePoint 2010 or 2013 farm and use the basic out-of-the-box actions without any time-limited expiration. I'm a big fan of the so-called "freemium" model and glad to see more SharePoint ISV's adopting it. Obviously, each vendor would like to you to purchase their product after giving it a spin but if you are satisfied with the no-cost features the hope is that you will provide some word-of-mouth validation in return.

If you are so inclined, give SPGA a try and see how it works for you. You can download it here. If you give it a go be sure to let Jeff and the team at PremierPoint know how you like it and any improvements they can make.

Another year, another TechEd over and done with. It was exciting to have a big technology conference back in the great State of Texas and the City of Houston did us all proud. Great times with great friends and lots of interesting discussions regarding SharePoint, Office 365, Azure, and a bunch of other cool products & technologies.

For those who attended my session on OAuth in SharePoint 2013, links to the slides and code samples can be found below. Thanks to everyone who dropped by, especially the four brave souls who volunteered for my human Token Handler demonstration. Many thanks!

This site is brought to you by BinaryWave in cooperation with Eric Shupps Eric Alan Shupps eshupps @eshupps The SharePoint Cowboy. We hope you enjoy the SharePoint-related content on topics such as performance, monitoring, administration, operations, support, business intelligence and more for SharePoint 2010, SharePoint 2013 and Office 365 created by Eric Shupps The SharePoint Cowboy. We also hope you will visit our product pages to learn more about SmartTrack, Operational Analytics for SharePoint, SharePoint monitoring, and SharePoint administration, while also discovering great offers from our partners.
Please visit the blog of Eric Alan Shupps, Twitter handle @eshupps, for more information on application development, the SharePoint community, SharePoint performance, and general technology topics. Eric Shupps Eric Alan Shupps eshupps @eshupps The SharePoint Cowboy is the founder and President of BinaryWave, a leading provider of operational support solutions for SharePoint. Eric Shupps Eric Alan Shupps eshupps @eshupps The SharePoint Cowboy has worked with SharePoint Products and Technologies since 2001 as a consultant, administrator, architect, developer and trainer. He is an advisory committee member of the Dallas/Ft. Worth SharePoint Community group and participating member of user groups throughout the United Kingdom. Eric Shupps Eric Alan Shupps eshupps @eshupps The SharePoint Cowboy has authored numerous articles on SharePoint, speaks at user group meetings and conferences around the world, and publishes a popular SharePoint blog at http://www.binarywave.com/blogs/eshupps.