使用更多 Active Directory 信息更新 SharePoint UserInfo 列表






4.45/5 (5投票s)
展示如何编写一个作业,使用更多 Active Directory 信息更新 UserInfo 列表。
引言
前段时间,我下载了一个 Web Part,它应该显示当前用户的天气。它被编码为查询 SiteUserInfoList
并提取用户的 WorkCity
、WorkState
和 WorkCountry
属性,以便正确地定位用户。我安装了这个 Web Part,发现它不起作用。这些属性在 Moss 的用户配置文件中,但不在 Site 集合的 SiteUserInfoList
中。编写 Web Part 的人显然不喜欢进行测试。那么,我该怎么办?我不想依赖 Moss 的用户配置文件,因为我希望我的所有 Web Part 都能在非 Moss 实现中工作。因此,我决定编写一个作业,每天晚上运行以使用更多 Active Directory 属性更新 SiteUserInfoList
。
另外,您是否厌倦了在将用户添加到组时收到“用户不存在或不唯一”错误?那么,这段代码还将更新 Active Directory 中缺失的每个用户的标题为“XX - <previousTitle>”。这是一种简单的方法,可以向您展示用户在 Active Directory 中缺失,以便在使用用户选择器对话框时,您可以防止自己收到该错误。
安装
首先,将构建目录复制到您农场中每个服务器的桌面上。以管理员身份运行“Install AD Updator.bat”。输入您要安装到的 Web 应用程序的名称,然后按 Enter。请确保一次只在一个服务器上运行此操作。
代码
该代码遍历 SharePoint 中的所有用户,然后从 Active Directory 中提取他们的信息。然后,它获取来自 Active Directory 的信息并更新特定的字段,例如 Title
、Phone
等。然后,它将剩余的信息(WorkCity
、WorkZip
等)存储在用户 UserInfo
项目的属性包中。
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);
}
}
}
现在,我们可以通过以下方式提取这些信息并在我们的 Web Part 中使用它(这段代码是基于我修改过的 WeatherWebPart
中的示例)
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;
}
就这样,很简单!