I am enumerating a Domain Local Group in Active Directory using:
Dim de As New DirectoryEntry("path")
Dim members As IADsMembers = DirectCast(de.Invoke("Members"), IADsMembers)
members.Filter = New Object() {"user"}
'Iterate over users.
members.Filter = New Object() {"grou开发者_如何学运维p"}
'Iterate over nested groups.
The Domain Local Group is not enumerating. I have checked members.Count
which equals 1.
Having looked in Active Directory there is a Foreign Security Principal which links to a Global Group in another domain. Research suggests that the only options for members.Filter
are user and group
, user
and group
.
How can I extract the Foreign Security Principal from this collection?
For the most part I have chosen to use the functionality provided by System.Directory.AccountManagement
in .NET 3.5 to enumerate a global group. If the object being enumerated is actually a Foreign Security Principal then the .NET 3.5 code does not suffice. Hopefully the following code will help someone else:
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
There is probably better ways of doing this but it works.
The fact that you have foreign security principal
in your domain suggests that your group member is actually from another forest. You need to make sure the account that you are using to run the code has permission to access the other forest.
If you are using .NET 3.5 or above, you should try using System.DirectoryService.AccountManagement.
I think GroupPrincipal.GetMembers should solve your problem. This MSDN link includes a sample on how to use this GroupPrincipal
. It allows you to specify getting the members recursively or not. It also mentions that you can get the members from different forest.
精彩评论