Active Directory:调整函数的性能以检索组成员

这篇文章是对以下内容的跟进:

Active Directory:DirectoryEntry成员列表 GroupPrincipal.GetMembers()

我有一个函数,它检索Active Directory中组的所有成员的distinguishedName属性。 此函数用于检索所有用户和组对象的大型脚本(总运行时间为7-10分钟)。 我的问题是distinguishedName上的下游SSIS查找非常慢。 这并不奇怪,因为它正在查找varchar(255)与UniqueIdentifier(16字节)。 我可以在源代码上执行SQL Select,然后使用Merge Join,这会加快速度。 但是,我注意到提取中存在潜在竞争条件(参见上面的运行时间),其中组成员存在而没有匹配的distinguishedName。 如果是这种情况,那么我需要解决这个问题; 但是,合并连接不会使加载失败,而查找可以设置为使加载失败。

所以,我需要通过distinguishedName动态获取guid。 但是,当我尝试使用下面的方法时,GetGroupMemberList函数的性能大幅下降。 是否有更好/更快的方式通过distinguishedName获取组成员guid?

方法(两个循环):

listGroupMemberGuid.Add(new DirectoryEntry("LDAP://" + member, null, null, AuthenticationTypes.Secure).Guid); listGroupMemberGuid.Add(new DirectoryEntry("LDAP://" + user, null, null, AuthenticationTypes.Secure).Guid); 

function:

 private List GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize) { // Variable declaration(s). List listGroupMemberDn = new List(); string strPath = strActiveDirectoryHost + "/"; const int intIncrement = 1500; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx var members = new List(); // The count result returns 350. var group = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure); //var group = new DirectoryEntry($"LDAP://{"EnterYourDomainHere"}/", null, null, AuthenticationTypes.Secure); while (true) { var memberDns = group.Properties["member"]; foreach (var member in memberDns) { members.Add(member.ToString()); } if (memberDns.Count < intIncrement) break; group.RefreshCache(new[] { $"member;range={members.Count}-*" }); } //Find users that have this group as a primary group var secId = new SecurityIdentifier(group.Properties["objectSid"][0] as byte[], 0); /* Find The RID (sure exists a best method) */ var reg = new Regex(@"^S.*-(\d+)$"); var match = reg.Match(secId.Value); var rid = match.Groups[1].Value; /* Directory Search for users that has a particular primary group */ var dsLookForUsers = new DirectorySearcher { Filter = string.Format("(primaryGroupID={0})", rid), SearchScope = SearchScope.Subtree, PageSize = 1000, SearchRoot = new DirectoryEntry(strActiveDirectoryHost) }; dsLookForUsers.PropertiesToLoad.Add("distinguishedName"); var srcUsers = dsLookForUsers.FindAll(); foreach (SearchResult user in srcUsers) { members.Add(user.Properties["distinguishedName"][0].ToString()); } return members; } 

更新1:

用于检索foreach中的DN的代码(searchResult):

 foreach (SearchResult searchResult in searchResultCollection) { string strDn = searchResult.Properties["distinguishedName"][0].ToString(); var de = new DirectoryEntry("LDAP://" + strDn, null, null, AuthenticationTypes.Secure); de.RefreshCache(new[] { "objectGuid" }); var guid = new Guid((byte[])de.Properties["objectGuid"].Value); } 

它总是会变慢,因为您必须再次与每个成员的Active Directory对话。 但是,您可以最大限度地减少它的流量。

我在监控网络流量的同时做了几次快速测试。 我比较了两种方法:

  1. DirectoryEntry上调用.Guid ,就像在代码中一样。
  2. 使用此方法:
 var de = new DirectoryEntry("LDAP://" + member, null, null, AuthenticationTypes.Secure); de.RefreshCache(new [] {"objectGuid"}); var guid = new Guid((byte[]) de.Properties["objectGuid"].Value); 

第二种方法的网络流量显着减少:第一个帐户的流量小于1/3,之后每个帐户的流量更少(似乎重用连接)。

我知道如果你先使用.Properties而不调用.RefreshCache ,它会拉出帐户的每个属性。 看起来好像在使用.Guid做同样的事情。

调用.RefreshCache(new [] {"objectGuid"}); 只获取objectGuid属性而没有其他内容并将其保存在缓存中。 然后,当您使用.Properties["objectGuid"]它已经在缓存中具有该属性,因此它不需要再建立任何网络连接。

更新:对于您在搜索中获得的内容,只需要请求objectGuid属性而不是distinguishedName

 dsLookForUsers.PropertiesToLoad.Add("objectGuid"); var srcUsers = dsLookForUsers.FindAll(); foreach (SearchResult user in srcUsers) { members.Add(new Guid((byte[])user.Properties["objectGuid"][0])); }