问题描述
这篇文章是对以下内容的跟进:
This post is a follow-up to the following:
Active Directory:DirectoryEntry 成员列表 <>GroupPrincipal.GetMembers()
我有一个函数可以检索 Active Directory 中某个组的所有成员的 distinctName 属性.此函数用于检索所有用户和组对象的大型脚本(总运行时间为 7-10 分钟).我的问题是,distinguishedName 上的下游 SSIS 查找速度非常慢.这并不奇怪,因为它正在查找 varchar(255) 与 UniqueIdentifier(16 字节).我可以在源代码上执行 SQL Select,然后 Merge Join,这会加快速度.但是,我注意到提取物中存在潜在的竞争条件(参见上面的运行时),其中存在组成员而没有匹配的专有名称.如果是这种情况,那么我需要解决这个问题;但是,Merge Join 不会使加载失败,而 Lookup 可以设置为使加载失败.
I have a function that retrieves the distinguishedName attribute for all members of a group in Active Directory. This function is used in a much large script that retrieves all user and group objects (total run time is 7-10 minutes). My problem here is that the downstream SSIS Lookup on the distinguishedName is extremely slow. This is not surprising due to the fact that it is looking up a varchar(255) versus UniqueIdentifier (16 bytes). I could do a SQL Select on the source and then Merge Join, which would speed things up. But, I am noticing a potential race condition (see run time above) in the extract where group members exist without a matching distinguishedName. If this is the case, then I need to address that; however, a Merge Join won't fail the load whereas a Lookup can be set to fail the load.
因此,我需要通过专有名称即时获取 guid.但是,当我尝试使用以下方法时,GetGroupMemberList 函数的性能大幅下降.是否有更好/更快的方法通过专有名称获取组成员 guid?
So, I need to get the guid on-the-fly via the distinguishedName. However, when I try to use the below method, the performance of the GetGroupMemberList function drops substantially. Is there a better/faster way to get the group member guid via the distinguishedName?
方法(对于两个循环):
listGroupMemberGuid.Add(new DirectoryEntry("LDAP://" + member, null, null, AuthenticationTypes.Secure).Guid);
listGroupMemberGuid.Add(new DirectoryEntry("LDAP://" + user, null, null, AuthenticationTypes.Secure).Guid);
功能:
private List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
{
// Variable declaration(s).
List<string> listGroupMemberDn = new List<string>();
string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
const int intIncrement = 1500; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
var members = new List<string>();
// The count result returns 350.
var group = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
//var group = new DirectoryEntry($"LDAP://{"EnterYourDomainHere"}/<GUID={strPropertyValue}>", 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(searchResult) 中检索 DN 的代码:
Code for retrieving the DN in the foreach(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 对话.但是,您可以最大限度地减少它的流量.
It will always be slower since you have to talk to Active Directory again for each member. But, you can minimize the amount of traffic that it does.
我做了几个快速测试,同时监控网络流量.我比较了两种方法:
I did a couple quick tests, while monitoring network traffic. I compared two methods:
- 在
DirectoryEntry
上调用.Guid
,就像在代码中一样. - 使用此方法:
- Calling
.Guid
on theDirectoryEntry
, like you have in your code. - Using this method:
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,之后的每个帐户甚至更少(似乎重用了连接).
The second method had significantly less network traffic: less than 1/3rd on the first account, and even less for each account after (it seems to reuse the connections).
我知道,如果您使用 .Properties
而不先调用 .RefreshCache
,它会拉取帐户的每个属性.似乎使用 .Guid
做同样的事情.
I know that if you use .Properties
without calling .RefreshCache
first, it will pull every attribute for the account. It seems like using .Guid
does the same thing.
调用 .RefreshCache(new [] {"objectGuid"});
只获取 objectGuid
属性,没有别的,并将其保存在缓存中.然后当您使用 .Properties["objectGuid"]
时,它已经在缓存中具有该属性,因此不需要再进行任何网络连接.
Calling .RefreshCache(new [] {"objectGuid"});
only gets the objectGuid
attribute and nothing else and saves it in the cache. Then when you use .Properties["objectGuid"]
it already has the attribute in the cache, so it doesn't need to make any more network connections.
更新:对于你在搜索中得到的那些,只需要 objectGuid
属性而不是 distinguishedName
:
Update:
For the ones you get in the search, just ask for the objectGuid
attribute instead of the distinguishedName
:
dsLookForUsers.PropertiesToLoad.Add("objectGuid");
var srcUsers = dsLookForUsers.FindAll();
foreach (SearchResult user in srcUsers)
{
members.Add(new Guid((byte[])user.Properties["objectGuid"][0]));
}
这篇关于Active Directory:调整功能的性能以检索组成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!