Second Life of a Hungarian SharePoint Geek

May 13, 2011

‘User cannot be found’ error solved using the SharePoint object model

Filed under: Administration, Bugs, Reflection, SP 2010 — Tags: , , , — Peter Holpar @ 21:24

In my recent post I wrote about the ‘User cannot be found‘ error on the Change site collection administrators page and how to find the source of the issue using a SQL query.

In the current post I would like to provide you a bit more supported and more automated solution using the server side SharePoint API and some Reflectioning.

In this approach we first gets the list of all admin and content web applications, then iterate through the site collection of each web apps.

  1. private void CheckSiteAdminsOnFarm()
  2. {
  3.  
  4.     // we check both admin and content sites
  5.     List<SPWebApplication> appsToCheck = SPWebService.AdministrationService.WebApplications.Union(
  6.         SPWebService.ContentService.WebApplications).ToList();
  7.  
  8.     // we iterate through all site collections of all apps
  9.     appsToCheck.ForEach(webApp => webApp.Sites.ToList().ForEach(site => CheckSiteAdmins(site, @"SPMMX\administrator")));
  10.  
  11. }

You can see that we provide a login name to the CheckSiteAdmins method. Admin users that cannot be resolved as an existing user will be replaced with this user account.

In CheckSiteAdmins we first have to initialize the site using the private InitSite method of the SPSite class. It is necessary to call  InitSite, since it populates the value of the private m_OwnerID and m_nSecondaryContactID fields. Next we read the int values of these fields and try to resolve the to user through our GetUserName method.

  1. private void CheckSiteAdmins(SPSite site, String adminUser)
  2. {
  3.     try
  4.     {
  5.         Console.WriteLine("Checking site: '{0}' ({1})", site.RootWeb.Title, site.Url);
  6.  
  7.         Type spSiteType = typeof(SPSite);
  8.  
  9.         // site must be initialized before accessing the contact info
  10.         MethodInfo mi_InitSite = spSiteType.GetMethod("InitSite",
  11.                         BindingFlags.NonPublic | BindingFlags.Instance, null,
  12.                         new Type[0], null);
  13.  
  14.         if (mi_InitSite != null)
  15.         {
  16.             mi_InitSite.Invoke(site, null);
  17.  
  18.             // get field info of m_OwnerID
  19.             FieldInfo fi_m_OwnerID = spSiteType.GetField("m_OwnerID",
  20.                     BindingFlags.NonPublic | BindingFlags.Instance);
  21.             // get field info of m_nSecondaryContactID
  22.             FieldInfo fi_m_nSecondaryContactID = spSiteType.GetField("m_nSecondaryContactID",
  23.                     BindingFlags.NonPublic | BindingFlags.Instance);
  24.  
  25.             String currentAdmin = String.Empty;
  26.             bool isFound = false;
  27.  
  28.             if (fi_m_OwnerID != null)
  29.             {
  30.                 int primaryContactId = (int)fi_m_OwnerID.GetValue(site);
  31.                 isFound = GetUserName(site, primaryContactId, out currentAdmin);
  32.                 Console.WriteLine("Primary: {0}; {1}", primaryContactId, currentAdmin);
  33.                 if (!isFound)
  34.                 {
  35.                     Console.WriteLine("Fix site owner to '{0}'", adminUser);
  36.                     site.Owner = site.RootWeb.EnsureUser(adminUser);
  37.                 }
  38.             }
  39.  
  40.             if (fi_m_nSecondaryContactID != null)
  41.             {
  42.                 int secondaryContactId = (int)fi_m_nSecondaryContactID.GetValue(site);
  43.                 isFound = GetUserName(site, secondaryContactId, out currentAdmin);
  44.                 Console.WriteLine("Secondary: {0}; {1}", secondaryContactId, currentAdmin);
  45.                 if (!isFound)
  46.                 {
  47.                     Console.WriteLine("Fix secondary contact to '{0}'", adminUser);
  48.                     site.SecondaryContact = site.RootWeb.EnsureUser(adminUser);
  49.                 }
  50.             }
  51.         }
  52.     }
  53.     catch (Exception ex)
  54.     {
  55.         Console.WriteLine(ex.Message);
  56.     }
  57. }

If the user set as the admin is invalid, we simply replace it with the default value passed in the adminUser parameter.

Side note: In the former post I wrote a few words about the internal GetByIDNoThrow method and the private FindUserNoThrow method of the SPUserCollection class. These method may help to create alternative ways to lookup the user, but it is important to let the caller method know, that we found no user because none was set or because the one that was set cannot be resolved. So passing back an SPUser instance with a simple null value is not a solution.

Our implementation of GetUserName method looks like illustrated by the following code block:

  1. private bool GetUserName(SPSite site, int userId, out String currentAdmin)
  2. {
  3.     currentAdmin = "Not specified";
  4.     bool isFound = true;
  5.  
  6.     if (userId != 0)
  7.     {
  8.         SPUser user = site.RootWeb.SiteUsers.Cast<SPUser>().AsQueryable().FirstOrDefault(usr => usr.ID == userId);
  9.         currentAdmin = (user == null) ? "Unknown user" : user.Name;
  10.         isFound = (user != null);
  11.     }
  12.  
  13.     return isFound;
  14. }

Running the code as part of a console application via calling the CheckSiteAdminsOnFarm method displays the current site owners and secondary contacts of all the sites of all the web applications, and replaces the invalid values if necessary.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: