2013-03-05 65 views
2

當我檢索本地WinNT組的成員時,無論如何不是全部成員被返回。我補充一下:如何獲取本地WinNT組的所有成員?

  • 的Active Directory用戶
  • Active Directory組

既有成功(見圖片),但只用戶出現之後。

enter image description here

的問題是:

  • 會發生什麼事,以增加羣體?
  • 查看代碼示例中的最後一個方法'GetMembers()'
  • 這是已知問題嗎?
  • 任何解決方法可用?

非常感謝!

string _domainName = @"MYDOMAIN"; 
string _basePath = @"WinNT://MYDOMAIN/myserver"; 
string _userName = @"MYDOMAIN\SvcAccount"; 
string _password = @"********"; 

void Main() 
{ 
    CreateGroup("lg_TestGroup"); 
    AddMember("lg_TestGroup", @"m.y.username"); 
    AddMember("lg_TestGroup", @"Test_DomainGroup"); 

    GetMembers("lg_TestGroup"); 
} 

// Method added for reference. 
void CreateGroup(string accountName) 
{ 
    using (DirectoryEntry rootEntry = new DirectoryEntry(_basePath, _userName, _password)) 
    { 
     DirectoryEntry newEntry = rootEntry.Children.Add(accountName, "group"); 
     newEntry.CommitChanges(); 
    } 
} 

// Add Active Directory member to the local group. 
void AddMember(string groupAccountName, string userName) 
{ 
    string path = string.Format(@"{0}/{1}", _basePath, groupAccountName); 
    using (DirectoryEntry entry = new DirectoryEntry(path, _userName, _password)) 
    { 
     userName = string.Format("WinNT://{0}/{1}", _domainName, userName); 
     entry.Invoke("Add", new object[] { userName }); 
     entry.CommitChanges(); 
    } 
} 

// Get all members of the local group. 
void GetMembers(string groupAccountName) 
{ 
    string path = string.Format(@"{0}/{1}", _basePath, groupAccountName); 
    using (DirectoryEntry entry = new DirectoryEntry(path, _userName, _password)) 
    { 
     foreach (object member in (IEnumerable) entry.Invoke("Members")) 
     { 
     using (DirectoryEntry memberEntry = new DirectoryEntry(member)) 
     { 
      string accountName = memberEntry.Path.Replace(string.Format("WinNT://{0}/", _domainName), string.Format(@"{0}\", _domainName)); 
      Console.WriteLine("- " + accountName); // No groups displayed... 
     } 
     } 
    } 
} 

更新#1 組成員的序列似乎是必不可少的。只要GetMembers()中的枚舉器在Active Directory組上絆倒,其餘項目也不會顯示。因此,如果在此示例中首先列出「Test_DomainGroup」,則GetMembers()根本不顯示任何內容。

回答

2

我知道這是一個老問題,你可能已經發現你所需要的答案,但以防萬一別人絆倒進行的跨這個...

你用你的DirectoryEntry的WINNT ADSI供應商[即。 WINNT:// MYDOMAIN/MYSERVER]具有與Windows域不在停留在舊的Windows 2000/NT功能級別(https://support.microsoft.com/en-us/kb/322692)的工作非常有限的能力。

在這種情況下,問題在於WinNT提供程序不知道如何處理全局或通用安全組(這在Windows NT中不存在,只要您將域級別提升到高於Windows 2000的混合級別模式)。因此,如果這些類型的任何組嵌套在本地組中,則通常會遇到類似於您所描述的問題。

我找到的唯一解決方案/解決方法是確定您要枚舉的組是否來自域,如果是,則切換到LDAP提供程序,該提供程序將在調用「成員」時正確顯示所有成員。

不幸的是我不知道的「易」的方式剛剛從使用WinNT提供使用使用你已經綁定到WinNT提供的DirectoryEntry LDAP提供切換。所以,在我工作的項目,我一般喜歡得到當前WINNT對象的SID,然後使用LDAP搜索域對象具有相同的SID。

對於Windows 2003+域您可以將SID字節數組轉換爲常用格式SDDL(S-1-5-21 ...),然後使用類似綁定到對象與匹配的SID:

Byte[] SIDBytes = (Byte[])memberEntry.Properties["objectSID"].Value; 
System.Security.Principal.SecurityIdentifier SID = new System.Security.Principal.SecurityIdentifier(SIDBytes, 0); 

memberEntry.Dispose(); 
memberEntry = new DirectoryEntry("LDAP://" + _domainName + "/<SID=" + SID.ToString() + ">"); 

對於Windows 2000域,你不能直接綁定到由SID的對象。因此,您必須將您的SID字節數組轉換爲帶有「\」前綴(\ 01 \ 06 \ 05 \ 16 \ EF \ A2 ..)的十六進制值數組,然後使用DirectorySearcher查找帶有匹配SID。做到這一點的方法看起來像這樣:

public DirectoryEntry FindMatchingSID(Byte[] SIDBytes, String Win2KDNSDomainName) 
{ 
    using (DirectorySearcher Searcher = new DirectorySearcher("LDAP://" + Win2KDNSDomainName)) 
    { 
     System.Text.StringBuilder SIDByteString = new System.Text.StringBuilder(SIDBytes.Length * 3); 

     for (Int32 sidByteIndex = 0; sidByteIndex < SIDBytes.Length; sidByteIndex++) 
      SIDByteString.AppendFormat("\\{0:x2}", SIDBytes[sidByteIndex]); 

     Searcher.Filter = "(objectSid=" + SIDByteString.ToString() + ")"; 
     SearchResult result = Searcher.FindOne(); 

     if (result == null) 
      throw new Exception("Unable to find an object using \"" + Searcher.Filter + "\"."); 
     else 
      return result.GetDirectoryEntry(); 
    } 
}