Вопрос: Как последовательно получить всех членов группы?
Контекст: я получаю все объекты, которые являются либо человеком, группой, контактом или компьютером:
Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))"
Теперь мне нужно получить всех членов групп. Для этого я разработал три метода; однако они возвращают разные результаты для одной и той же группы, и я не уверен, почему. Я подозреваю, что это может быть вызвано вложенными группами (т.е. группами внутри групп). Его отладка представляет собой сложную задачу, поскольку некоторые группы содержат так много участников, что время ожидания отладчика истекает, и он не показывает никаких результатов.
Метод 1 и 2 медленный. Способ 3 быстрый. Поэтому я предпочитаю использовать метод 3.
Group Name Retrieval Method Recursive Search Count Members Comment
Group1 AccountManagement TRUE 505
Group1 AccountManagement FALSE 505
Group1 DirectoryServices N/A 101
Group2 AccountManagement TRUE 440 Contains group name 'Group3'
Group2 AccountManagement FALSE 440 Contains group name 'Group3'
Group2 DirectoryServices N/A 100 Contains group name 'Group3'
Group3 AccountManagement TRUE 101 All Group3
Group3 AccountManagement FALSE 2 All Group3
Group3 DirectoryServices N/A 2 1 user 1 group (Group2)
Метод 1 и 2. Получите участников группы с помощью S.DS.AM
, где для GetMembers() установлено значение true или false соответственно: https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement(v=vs.110).aspx
private static List<Guid> GetGroupMemberList(string strPropertyValue, string strDomainController, bool bolRecursive)
{
List<Guid> listGroupMemberGuid = null;
GroupPrincipal groupPrincipal = null;
PrincipalSearchResult<Principal> listPrincipalSearchResult = null;
List<Principal> listPrincipalNoNull = null;
PrincipalContext principalContext = null;
ContextType contextType;
IdentityType identityType;
try
{
listGroupMemberGuid = new List<Guid>();
contextType = ContextType.Domain;
principalContext = new PrincipalContext(contextType, strDomainController);
identityType = IdentityType.Guid;
groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);
if (groupPrincipal != null)
{
listPrincipalSearchResult = groupPrincipal.GetMembers(bolRecursive);
listPrincipalNoNull = listPrincipalSearchResult.Where(item => item.Name != null).ToList();
foreach (Principal principal in listPrincipalNoNull)
{
listGroupMemberGuid.Add((Guid)principal.Guid);
}
}
return listGroupMemberGuid;
}
catch (MultipleMatchesException)
{
throw new MultipleMatchesException(strPropertyValue);
}
catch (Exception ex)
{
throw ex;
}
finally
{
listGroupMemberGuid = null;
listPrincipalSearchResult.Dispose();
principalContext.Dispose();
groupPrincipal.Dispose();
}
}
Способ 3. Получите участников группы с помощью S.DS.AD
: https://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectory(v=vs.110).aspx
private static List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
{
List<string> listGroupMemberDn = new List<string>();
string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
DirectoryEntry directoryEntryGroup;
DirectoryEntry directoryEntryGroupMembers;
DirectorySearcher directorySearcher;
SearchResultCollection searchResultCollection;
DataTypeConverter objConverter = null;
objConverter = new DataTypeConverter();
try
{
directoryEntryGroup = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
directoryEntryGroup.RefreshCache();
}
catch (Exception ex)
{
throw ex;
}
try
{
directorySearcher = new DirectorySearcher(directoryEntryGroup)
{
//Filter = "(objectCategory=group)", // Group
SearchScope = SearchScope.Subtree,
PageSize = intActiveDirectoryPageSize,
};
directorySearcher.PropertiesToLoad.Add("objectGUID");
searchResultCollection = directorySearcher.FindAll();
}
catch (Exception ex)
{
throw ex;
}
try
{
foreach (SearchResult searchResult in searchResultCollection)
{
directoryEntryGroupMembers = searchResult.GetDirectoryEntry();
foreach (object objGroupMember in directoryEntryGroupMembers.Properties["member"])
{
listGroupMemberDn.Add((string)objGroupMember);
}
}
return listGroupMemberDn;
}
catch (Exception ex)
{
throw ex;
}
finally
{
listGroupMemberDn = null;
strPath = null;
directoryEntryGroup.Dispose();
directoryEntryGroupMembers = null;
directorySearcher.Dispose();
searchResultCollection.Dispose();
objConverter = null;
}
}
Способ 4: (Цикл с реализацией метода GetNextChunk())
private static List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
{
// Variable declaration(s).
List<string> listGroupMemberDn = new List<string>();
string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
string strMemberPropertyRange = null;
DirectoryEntry directoryEntryGroup = null;
DirectorySearcher directorySearcher = null;
SearchResultCollection searchResultCollection = null;
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
const int intIncrement = 1500;
// Load the DirectoryEntry.
try
{
// Setup a secure connection with Active Directory (AD) using Kerberos by setting the directoryEntry with AuthenticationTypes.Secure.
directoryEntryGroup = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
// Load the property values for this DirectoryEntry object into the property cache.
directoryEntryGroup.RefreshCache();
}
catch (Exception)
{ }
#region Method1
// Enumerate group members.
try
{
// Check to see if the group has any members.
if (directoryEntryGroup.Properties["member"].Count > 0)
{
int intStart = 0;
while (true)
{
// End of the range.
int intEnd = intStart + intIncrement - 1;
strMemberPropertyRange = string.Format("member;range={0}-{1}", intStart, intEnd);
directorySearcher = new DirectorySearcher(directoryEntryGroup)
{
// Set the Filter criteria that is used to constrain the search within AD.
Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))", // User, Contact, Group, Computer objects
// Set the SearchScope for how the AD tree is searched (Default = Subtree).
SearchScope = SearchScope.Base,
// The PageSize value should be set equal to the PageSize that is set by the AD administrator (Default = 0).
PageSize = intActiveDirectoryPageSize,
PropertiesToLoad = { strMemberPropertyRange }
};
try
{
// Populate the searchResultCollection with all records within AD that match the Filter criteria.
searchResultCollection = directorySearcher.FindAll();
foreach (SearchResult searchResult in searchResultCollection)
{
var membersProperties = searchResult.Properties;
var membersPropertyNames = membersProperties.PropertyNames.OfType<string>().Where(n => n.StartsWith("member;"));
foreach (var propertyName in membersPropertyNames)
{
// Get all members from the ranged result.
var members = membersProperties[propertyName];
foreach (string memberDn in members)
{
// Add the member's "distinguishedName" attribute value to the list.
listGroupMemberDn.Add(memberDn);
}
}
}
}
catch (DirectoryServicesCOMException)
{
// When the start of the range exceeds the number of available results, an exception is thrown and we exit the loop.
break;
}
// Increment for the next range.
intStart += intIncrement;
}
}
// return the listGroupMemberDn;
return listGroupMemberDn;
}
#endregion
finally
{
// Cleanup objects.
listGroupMemberDn = null;
strPath = null;
strMemberPropertyRange = null;
directoryEntryGroup.Dispose();
directorySearcher.Dispose();
searchResultCollection.Dispose();
}
}