По большей части я решил использовать функциональность, предоставляемую System.Directory.AccountManagement
в .NET 3.5, для перечисления глобальной группы. Если перечисляемый объект на самом деле является принципалом внешней безопасности, тогда кода .NET 3.5 недостаточно. Надеюсь, следующий код поможет кому-то еще:
Private Sub EnumerateGlobalGroup(ByVal distinguishedName As String)
Try
Using context As New PrincipalContext(ContextType.Domain, GetDomainName(distinguishedName))
Using gp As GroupPrincipal = GroupPrincipal.FindByIdentity(context, IdentityType.DistinguishedName, distinguishedName)
Dim groupMembers As PrincipalSearchResult(Of Principal) = gp.GetMembers(True)
For Each member As Principal In groupMembers
Console.WriteLine(member.DisplayName)
Select Case member.StructuralObjectClass
Case "user"
Console.WriteLine("user")
Case "group"
Console.WriteLine("group")
End Select
Next
End Using
End Using
Catch ex As Exception
If Not TypeOf ex Is PrincipalOperationException Then Throw ex
'Get this far then enumerating Foreign Security Principal.
Dim groupEntry As New DirectoryEntry("LDAP://" & distinguishedName)
Dim members As Object = groupEntry.Invoke("Members")
For Each member As Object In CType(members, IEnumerable)
Dim memberEntry As New DirectoryEntry(member)
Console.WriteLine(memberEntry.Name)
Dim sid As New SecurityIdentifier(DirectCast(memberEntry.InvokeGet("objectSid"), Byte()), 0)
Dim account As NTAccount = sid.Translate(GetType(NTAccount))
Console.WriteLine(account.ToString)
Dim memberDistinguishedName As String = GetDistinguishedName(account.ToString)
EnumerateGlobalGroup(memberDistinguishedName)
Next
End Try
End Sub
Private Function GetDomainName(ByVal dn As String) As String
Dim dnParts As String() = dn.Split(Char.Parse(","))
For Each d As String In dnParts
If d.StartsWith("DC") Then Return d.ToUpper().Replace("DC=", Nothing)
Next
Return Nothing
End Function
Private Function GetDistinguishedName(ByVal accountName As String) As String
Dim nameTranslate = New ActiveDs.NameTranslate()
nameTranslate.Set(ActiveDs.ADS_NAME_TYPE_ENUM.ADS_NAME_TYPE_NT4, accountName)
Return nameTranslate.Get(ActiveDs.ADS_NAME_TYPE_ENUM.ADS_NAME_TYPE_1779)
End Function
Возможно, есть лучшие способы сделать это , но это работает .