Click here to Skip to main content
Click here to Skip to main content
Go to top

Update SharePoint UserInfo List with More Active Directory Info

, 19 Mar 2009
Rate this:
Please Sign up or sign in to vote.
Shows how to write a job that updates the UserInfo list with more Active Directory information.

Introduction

A little while back, I downloaded a Web Part that was supposed to show the current user's weather. It was coded to query the SiteUserInfoList and pull back the user's WorkCity, WorkState, and WorkCountry properties so that it could correctly locate the user. I installed the Web Part and found that it didn't work. Those properties are in Moss' User Profile but not in the Site collection's SiteUserInfoList. The person who coded the Web Part obviously didn't like to do testing. So, what was I to do? I didn't want to resort to Moss' User Profile because I want all my Web Parts to work for non-Moss implementations. So, I decided to just write a job that would run every night to update the SiteUserInfoList with more Active Directory properties.

Also, are you tired of getting "User does not exist or is not unique" errors when adding users to groups? Well, this code will also update the title of every user that is missing in Active Diretory to "XX - <previousTitle>". This is an easy way to expose to you that the user is missing in Active Directory so that when you are using the User Selector dialog, you can prevent yourself from getting that error.

UserDialog.png

Installation

First, copy the build directory to the desktop of each server in your farm. Run "Install AD Updator.bat" as Administrator. Type in the name of your Web Application you want to install to, click Enter. Make sure you only run this on one server at a time.

The Code

The code runs through all the users in SharePoint and then pulls their information from Active Directory. It then takes the info from Active Directory and updates specific fields like Title, Phone, and etc. Then, it stores the rest of the info (WorkCity, WorkZip, and etc.) in the property bag of the user's UserInfo item.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using System.Diagnostics;
using Microsoft.SharePoint.Utilities;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Security.Principal;
namespace Mullivan.SharePoint.Jobs
{
    public class AdUserInfoUpdateJobDefinition : SPJobDefinition
    {
        internal const string _JOBNAME = "AD User Info Update Job";
        public AdUserInfoUpdateJobDefinition () : base() { }
        public AdUserInfoUpdateJobDefinition(SPWebApplication webApp)
            : base(_JOBNAME, webApp, null, SPJobLockType.Job)
        {
            this.Title = _JOBNAME;
        }
        public override void Execute(Guid targetInstanceId)
        {
            try
            {
                DirectoryEntry domain = GetDomainEntry();
                if (domain == null)
                    throw new Exception("Domain not found.");
                foreach (SPSite site in this.WebApplication.Sites)
                {
                    using (SPWeb web = site.RootWeb)
                    {
                        SPListItemCollection userItems = web.SiteUserInfoList.Items;
                        for (int i = 0; i < userItems.Count; i++)
                        {
                            try
                            {
                                double progress = ((double)(i + 1)) / 
                                                   (double)userItems.Count;
                                UpdateProgress(Convert.ToInt32(progress * 100));
                                SPListItem userItem = userItems[i];
                       
                                SPUser user = web.SiteUsers.GetByID(userItem.ID);
                                if (user == null)
                                    throw new Exception(string.Format(
                                      "User account {0} not found in site {1}.", 
                                      userItem.Name, site.Url));
                                DateTime dtUserItemUpdated = 
                                   (DateTime)userItem["Modified"];
                                if (IsPerson(userItem) && !IsSystem(user))
                                {
                                    AdUserInfo userInfo = GetUserInfo(user, domain);
                                    if (userInfo == null || !userInfo.IsActive)
                                    {
                                        string jobTitle = (string)userItem["JobTitle"];
                                        if (string.IsNullOrEmpty(jobTitle))
                                            jobTitle = string.Empty;
                                        if (!jobTitle.StartsWith("XX - "))
                                        {
                                            jobTitle = string.Format("XX - {0}", jobTitle);
                                            userItem["JobTitle"] = jobTitle;
                                            userItem.Update();
                                        }
                                    }
                                    else
                                    {
                                        object updateFlag = 
                                           userItem.Properties["AdUpdateFlag"];
                                        if (userInfo.LastModified > dtUserItemUpdated
                                            || updateFlag == null)
                                        {
                                            userItem.Properties["AdUpdateFlag"] = 1;
                                            if (userInfo.Email != null)
                                            {
                                                userItem["EMail"] = userInfo.Email;
                                                user.Email = userInfo.Email;
                                            }
                                            if (userInfo.Department != null)
                                                userItem["Department"] = userInfo.Department;
                                            if (userInfo.JobTitle != null)
                                                userItem["JobTitle"] = userInfo.JobTitle;
                                            else
                                            {
                                                string val = (string)userItem["JobTitle"];
                                                if (val != null)
                                                {
                                                    if (val.StartsWith("XX - "))
                                                        userItem["JobTitle"] = 
                                                           val.Substring(5, val.Length - 5);
                                                }
                                            }
                                            if (userInfo.FirstName != null)
                                                userItem["FirstName"] = userInfo.FirstName;
                                            if (userInfo.LastName != null)
                                                userItem["LastName"] = userInfo.LastName;
                                            if (userInfo.WorkPhone != null)
                                                userItem["WorkPhone"] = userInfo.WorkPhone;
                                            if (userInfo.Office != null)
                                                userItem["Office"] = userInfo.Office;
                                            if (userInfo.WorkZip != null)
                                                userItem.Properties["WorkZip"] = 
                                                                    userInfo.WorkZip;
                                            if (userInfo.WorkCity != null)
                                                userItem.Properties["WorkCity"] = 
                                                                    userInfo.WorkCity;
                                            if (userInfo.WorkState != null)
                                                userItem.Properties["WorkState"] = 
                                                                    userInfo.WorkState;
                                            if (userInfo.WorkCountry != null)
                                                userItem.Properties["WorkCountry"] = 
                                                                    userInfo.WorkCountry;
                                            userItem.Update();
                                            user.Update();
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Logging.ServiceLog.LogException(_JOBNAME, ex);
                            }
                        }
                        web.Dispose();
                    }
                    site.Dispose();
                }
            }
            catch (Exception ex)
            {
                Logging.ServiceLog.LogException(_JOBNAME, ex);
            }
        }
        private bool IsSystem(SPUser user)
        {
            if (user.ID.Equals(1073741823))
                return true;
            if (user.LoginName == null)
                return true;
            if(user.LoginName.ToLower().StartsWith("nt authority"))
                return true;
            if (user.LoginName.ToLower().StartsWith("system"))
                return true;
            return false;
        }
        private AdUserInfo GetUserInfo(SPUser user, DirectoryEntry domain)
        {
            string id = user.Sid;
            bool localMachine = domain.Path.StartsWith("WinNT");
            string userFlagProperty = "userAccountControl";
            if (localMachine)
                userFlagProperty = "UserFlags";
            DirectoryEntry deUser = FindUser(id, domain);
            if (deUser != null)
            {
                AdUserInfo adUserInfo = new AdUserInfo();
                adUserInfo.IsActive = true;
                if (localMachine)
                {
                    //For testing purposes... Production Environment should be using
                    // Active Directory
                    adUserInfo.LastModified = DateTime.Now;
                    string value = GetValue("FullName", deUser);
                    if (!string.IsNullOrEmpty(value))
                    {
                        string[] vals = value.Split(new char[1] { ' ' }
                            , StringSplitOptions.RemoveEmptyEntries);
                        if (vals.Length > 0)
                            adUserInfo.FirstName = vals[0];
                        if (vals.Length > 1)
                            adUserInfo.LastName = vals[vals.Length - 1];
                    }
                    adUserInfo.WorkCity = "St Louis";
                    adUserInfo.WorkState = "MO";
                    adUserInfo.WorkZip = "63141";
                    
                }
                else
                {
                    DateTime dtModified = DateTime.Now;
                    if (DateTime.TryParse(GetValue("whenChanged", deUser), 
                                          out dtModified))
                        adUserInfo.LastModified = dtModified;
                    else
                        adUserInfo.LastModified = DateTime.Now;
                    adUserInfo.LastName = GetValue("sn", deUser);
                    adUserInfo.FirstName = GetValue("givenName", deUser);
                    adUserInfo.Name = GetValue("sAMAccountName", deUser);
                    adUserInfo.Office = GetValue("physicalDeliveryOfficeName", deUser);
                    adUserInfo.WorkPhone = GetValue("telephoneNumber", deUser);
                    adUserInfo.Department = GetValue("department", deUser);
                    adUserInfo.Email = GetValue("mail", deUser);
                    adUserInfo.JobTitle = GetValue("title", deUser);
                    adUserInfo.WorkCity = GetValue("l", deUser);
                    adUserInfo.WorkState = GetValue("st", deUser);
                    adUserInfo.WorkCountry = GetValue("c", deUser);
                    adUserInfo.WorkZip = GetValue("postalCode", deUser);
                }
                string userAC = GetValue(userFlagProperty, deUser);
                int userValue = 0;
                if(int.TryParse(userAC, out userValue))
                {
                    try
                    {
                        AdUserAccountControl userAccountControl = 
                                            (AdUserAccountControl)userValue;
                        adUserInfo.IsActive = 
                            //Make sure it's not disabled
                            ((userAccountControl & AdUserAccountControl.ACCOUNTDISABLE) 
                                        != AdUserAccountControl.ACCOUNTDISABLE)
                            //Make sure it's a normal account
                            && ((userAccountControl & 
                                  AdUserAccountControl.NORMAL_ACCOUNT) == 
                                  AdUserAccountControl.NORMAL_ACCOUNT);
                    }
                    catch (Exception ex)
                    {
                        Logging.ServiceLog.LogException(_JOBNAME, ex);
                    }
                }
                return adUserInfo;
            }
            else
                return null;
        }
        private string GetValue(string propertyName, DirectoryEntry deUser)
        {
            if (deUser.Properties.Contains(propertyName))
            {
                PropertyValueCollection pvc = deUser.Properties[propertyName];
                if (pvc.Count > 0)
                {
                    object objValue = pvc[0];
                    if (objValue != null)
                        return objValue.ToString();
                }
            }
            return null;
        }
        private DirectoryEntry FindUser(string id, DirectoryEntry domain)
        {
            if (!domain.Path.StartsWith("WinNT"))
            {
                DirectorySearcher search = new DirectorySearcher(domain);
                search.Filter = 
                  string.Format("(&(objectClass=person)(objectSid={0}))", id);
                SearchResult result = search.FindOne();
                if(result != null)
                    return result.GetDirectoryEntry();
            }
            else
            {
                foreach (DirectoryEntry de in domain.Children)
                {
                    SecurityIdentifier si = new SecurityIdentifier(
                        (byte[])de.Properties["objectSid"][0], 0);
                    if (string.Compare(si.Value, id, true) == 0)
                        return de;
                }
            }
            return null;
        }
        private DirectoryEntry GetDomainEntry()
        {
            try
            {
                return Domain.GetComputerDomain().GetDirectoryEntry();
            }
            catch(Exception ex)
            {
                Logging.ServiceLog.LogException(_JOBNAME, ex);
#if SULLYSERVER
                DirectoryEntry localMachine = new DirectoryEntry(
                    string.Format("WinNT://{0},Computer", Environment.MachineName));
                return localMachine;
#else
                return null;
#endif
            }
        }
        private bool IsPerson(SPListItem userItem)
        {
            string contentType = userItem.ContentType.Name;
            if (!contentType.Equals("Person"))
                return false;
            return true;
        }
        private void Trace(string message)
        {
            System.Diagnostics.Trace.WriteLine(message, _JOBNAME);
        }
    }
}

We can now pull this information out and use it in our Web Parts by doing the following (this code is an example taken from the WeatherWebPart that I modified):

private bool SetUserLocation()
{
    try
    {
        SPWeb web = SPContext.Current.Web;
        SPUser u = web.SiteUsers[web.CurrentUser.LoginName];
        SPList userList = web.SiteUserInfoList;
        SPListItem uItem = userList.Items.GetItemById(u.ID);
       
        if (uItem != null)
        {
            string strZip = uItem.Properties["WorkZip"] as string;
            if (!string.IsNullOrEmpty(strZip))
                this.Zip = strZip;
            return true;
        }
    }
    catch
    {
        this.Zip = DEFAULT_ZIP;
    }
    return false;
}

There you go, pretty simple!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sike Mullivan
Software Developer (Senior)
United States United States
I am a Sr SharePoint Developer in Saint Louis, MO. I've been developing professionally for about four years now. For three years I worked for a Document Imaging company that developed applications for Scanning, Indexing, Migrating, and Searching SharePoint (MOSS, WSS). I'm now working on a team for a Cable company that customizes their internal and external SharePoint implementations.

Comments and Discussions

 
QuestionWas wondering.... [modified] Pinmembercccpd13-Oct-11 8:17 
Generalran the code PinmemberUri shk10-Oct-10 5:02 
Hi Sike,
 
installed the code as you directed, got operation completed succesfully, but i don't understand in which point this tool starts working.
 
My main issue is the fact users arent added automatically to the list, and i was hoping this will be part of that solution.
 
Thank you, Uri
GeneralRe: ran the code PinmemberSike Mullivan11-Oct-10 2:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 19 Mar 2009
Article Copyright 2009 by Sike Mullivan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid