SharePoint 2007 keeps track of Active Directory (AD) users and AD Groups in its own user database. There is an automatic synchronization that happens every night (by default) to import AD entities to the user database so that changes in AD can be brought into SharePoint. We ran into a situation that a few of the AD Groups in a client environment needed to be renamed. After the rename and the nightly synchronisation, we did not see the new AD Group names in SharePoint.

For example, there were some SharePoint Groups that had the AD Groups added but the old AD Group names were still being displayed. Forcing synchronization of user data did not help and we did not find any OOTB way to change the AD Group name. This is where a stsadm extension can help. As it turns out, SharePoint also stores the user data in the User Info List for which there is no user interface to manage data inside.

The following code sample allows you to update an AD Group entity in the list so that SharePoint will have the latest info.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.StsAdmin;
using Microsoft.SharePoint.Administration;

namespace Habanero.StsAdm.Command
{
	public class UpdateAdGroup : ISPStsadmCommand
	{

		const string urlKey = "url";
		const string oldLoginKey = "oldlogin";
		const string newLoginKey = "newlogin";
		const string debugKey = "debug";

		/// <summary>
		/// Display Help Message to the console
		/// 
		public string GetHelpMessage(string commands)
		{
			StringBuilder help = new StringBuilder();

			// Missing command(s)
			string[] commandsArray = commands.Split(',');
			foreach (string command in commandsArray)
			{
				help.Append(string.Format("Missing required argument: {0}.\n", command));
			}

			// Purpose and usage help
			help.Append(@"


stsadm -o gc-updateadgroup
       -url <site>
       -oldlogin <old>
       -newlogin <new>
");

			return help.ToString();
		}


		public int Run(string command, StringDictionary keyValues, out string output)
		{
			string url = keyValues[urlKey];
			string oldLogin = keyValues[oldLoginKey];
			string newLogin = keyValues[newLoginKey];

			if (keyValues[debugKey] != null)
			{
				System.Diagnostics.Debugger.Launch();  // this will prompt the user to identify a debugger for debugging session
			}

			// Validate that required commands are supplied
			if (string.IsNullOrEmpty(url))
			{
				output = this.GetHelpMessage(urlKey);
			}
			else if (string.IsNullOrEmpty(oldLogin))
			{
				output = this.GetHelpMessage(oldLoginKey);
			}
			else if (string.IsNullOrEmpty(newLogin))
			{
				output = this.GetHelpMessage(newLoginKey);
			}
			else
			{
				// Execute the command
				output = this.ExecuteCommand(url, oldLogin, newLogin);
			}

			return 0;
		}

		private string ExecuteCommand(string url, string oldLogin, string newLogin)
		{
			StringBuilder returnValue = new StringBuilder();
			using (SPSite site = new SPSite(url))
			{
				using (SPWeb web = site.OpenWeb())
				{

					UpdateUserInfoList(web, oldLogin, newLogin);
					returnValue.Append(string.Format("User Info List has \"{0}\" updated to \"{1}\"", oldLogin, newLogin));
					returnValue.Append(Environment.NewLine);

					ReAddSiteUser(site, oldLogin, newLogin);
					returnValue.Append(string.Format("AD Group \"{0}\" has been readded to \"{1}\"", newLogin, url));
					returnValue.Append(Environment.NewLine);
				}
			}
			return returnValue.ToString();
		}

		/// <summary>
		/// Add the AD entity to the site
		/// 
		private void ReAddSiteUser(SPSite site, string oldLogin, string newLogin)
		{
			IEnumerable<spgroup> groups = GetUserAssignments(site, newLogin, oldLogin);
			AddUser(site, newLogin, groups);
		}

		/// <summary>
		/// Update the User Info List in the web by replacing the oldLogin with the newLogin
		/// 
		private void UpdateUserInfoList(SPWeb web, string oldLogin, string newLogin)
		{
			Console.WriteLine(string.Format("Updating User Info List on {0}", web.Url));

			List<string> fieldTitles = new List<string>();
			fieldTitles.Add("Title");
			fieldTitles.Add("Name");
			fieldTitles.Add("LinkTitle");
			fieldTitles.Add("LinkTitleNoMenu");
			fieldTitles.Add("ImnName");
			fieldTitles.Add("NameWithPicture");
			fieldTitles.Add("NameWithPictureAndDetails");
			fieldTitles.Add("EditUser");
			fieldTitles.Add("ContentTypeDisp");
			fieldTitles.Add("AccountName");

			SPList userInfoList = web.SiteUserInfoList;
			foreach (SPItem item in userInfoList.Items)
			{
				foreach (string fieldTitle in fieldTitles)
				{
					if (item.Fields.ContainsField(fieldTitle))
					{
						// only update the fields if it is not null.
						if (item[fieldTitle] != null && item[fieldTitle].ToString().Equals(oldLogin, StringComparison.InvariantCultureIgnoreCase))
						{
							try
							{
								Console.WriteLine(string.Format("Updating [{0}]: {1}", fieldTitle, item[fieldTitle]));
								item[fieldTitle] = newLogin;
								item.Update();
							}
							catch (Exception ex)
							{
								Console.WriteLine(string.Format("Error: {0}", ex.Message));
								Console.WriteLine(string.Format("Source: {0}", fieldTitle));
								continue;
							}
						}
					}
				}
			}
		}


		#region Helper Methods
		/// <summary>
		/// Add user to the current web
		/// 
		static void AddUser(SPSite site, string loginName, IEnumerable<spgroup> groups)
		{
			using (SPWeb web = site.OpenWeb())
			{
				web.AllowUnsafeUpdates = true;
				SPUser user = web.EnsureUser(loginName);
				foreach (SPGroup group in groups)
				{
					group.AddUser(user);
				}
				web.AllowUnsafeUpdates = false;
			}
		}

		/// <summary>
		/// Enumerates and return a collection of SPGroups the user belongs to
		/// 
		static IEnumerable<spgroup> GetUserAssignments(SPSite site, string loginName, string displayName)
		{
			//  Check unique permission
			List<spgroup> groups = new List<spgroup>();

			foreach (SPWeb childWeb in site.AllWebs)
			{
				groups.AddRange(
					CheckUniquePermission(childWeb, loginName, displayName)
					);
				childWeb.Dispose();
			}

			return groups;
		}

		/// <summary>
		/// Returns a collection of SPGroup in the current web if it has unique permission
		/// 
		static IEnumerable<spgroup> CheckUniquePermission(SPWeb web, string loginName, string displayName)
		{
			List<spgroup> groups = new List<spgroup>();

			if (web.HasUniqueRoleAssignments)
			{
				foreach (SPGroup group in web.Groups)
				{
					if (GetUser(group.Users, loginName, displayName) != null)
					{
						groups.Add(group);
					}
				}
			}
			return groups;
		}

		/// <summary>
		/// Returns a SPUser object if the user exists in the collection of SPUsers and if the Name property matches the displayName.  Else it will return null.
		/// 
		static SPUser GetUser(SPUserCollection users, string loginName, string displayName)
		{
			SPUser user = null;
			user = users[loginName];
			if (!user.Name.Equals(displayName, StringComparison.InvariantCultureIgnoreCase))
				user = null;
			return user;
		}
		#endregion
	}
}

Share