2011-04-21 33 views
0

我使用Active Directory中枚举域本地组:ActiveDs.IADsMembers - 枚举全局组包含一个外部安全主体

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() {"group"} 
'Iterate over nested groups. 

域本地组不枚举。我检查了members.Count等于1.

查看Active Directory中有一个外部安全主体,它链接到另一个域中的全局组。研究表明,members.Filter的唯一选项是user and group,usergroup

如何从此集合中提取外部安全主体?

回答

2

大多数情况下,我选择使用.NET 3.5中的System.Directory.AccountManagement提供的功能来枚举全局组。如果被枚举的对象实际上是一个外部安全主体,那么.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 

有这样的可能是更好的方式,但它的工作原理

1

您的域中有foreign security principal这一事实表明您的组成员实际上来自另一个森林。您需要确保您用于运行代码的帐户有权访问其他林。

如果您使用的是.NET 3.5或更高版本,则应该尝试使用System.DirectoryService.AccountManagement

我认为GroupPrincipal.GetMembers应该可以解决你的问题。这MSDN link包括如何使用此GroupPrincipal示例。它允许你指定递归地获取成员。它还提到你可以从不同的森林中获得成员。

+0

我很高兴能够在.NET 3.5中使用所有这些漂亮的包装器,这让我感到很沮丧。如果全局组包含FSP,则发现FindByIdentity失败。 – youwhut 2011-05-12 09:04:44