SharePoint My Site Deletion and the Person.aspx Redirect Problem
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:
<asp:Content contentplaceholderid="PlaceHolderPageTitleInTitleArea" runat="server">
<SPSWC:PersonalSpaceRedirect runat="server" />
<SPSWC:LabelLoc TextLocId="My SiteContentText" runat="server" />
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):
namespace BinaryWave.SP.My Site
public class PageRedirector : WebControl
protected override void OnInit(EventArgs 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()
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())
catch (System.Exception ex)
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.
<?xml version="1.0" encoding="utf-8"?>
<Control Id="AdditionalPageHead" ControlAssembly="BinaryWave.SP.My Site, Version=22.214.171.124, Culture=neutral, PublicKeyToken=3a29866fd9ac8366" ControlClass="BinaryWave.SP.My Site.PageRedirector" />
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.
SmartTrack Operational Analytics for SharePoint