我有一个域本地组,它是林A中域A的一部分。
我正在尝试迭代这个组中的所有成员。它迭代遍历林A的所有域,但不会迭代域B中域B中的任何成员。
是从不同的林开始迭代相同代码的唯一方法吗?
我们已尝试使用System.DirectoryServices.AccountManagement
类,但它们和Windows Server 2012域控制器似乎存在问题。
private List<User> getUsersInGroup(string groupDN)
{
var users = new List<User>();
using (DirectoryEntry de = new DirectoryEntry("GC://rootDSE"))
{
var rootName = de.Properties["rootDomainNamingContext"].Value.ToString();
using (var userBinding = new DirectoryEntry("GC://" + rootName))
{
using (DirectorySearcher adSearch = new DirectorySearcher(userBinding))
{
adSearch.ReferralChasing = ReferralChasingOption.All;
adSearch.Filter = String.Format("(&(memberOf={0})(objectClass=person))", groupDN);
adSearch.PropertiesToLoad.Add("distinguishedName");
adSearch.PropertiesToLoad.Add("givenname");
adSearch.PropertiesToLoad.Add("samaccountname");
adSearch.PropertiesToLoad.Add("sn");
adSearch.PropertiesToLoad.Add("title");
adSearch.PropertiesToLoad.Add("displayName");
adSearch.PropertiesToLoad.Add("department");
using (var searchResults = adSearch.FindAll())
{
foreach (SearchResult result in searchResults)
{
User u = new User();
u.UserName = result.Properties["samaccountname"][0].ToString();
u.DistinguishedName = result.Properties["distinguishedName"][0].ToString();
if (result.Properties.Contains("title"))
{
u.Title = result.Properties["title"][0].ToString();
}
if (result.Properties.Contains("department"))
{
u.Department = result.Properties["department"][0].ToString();
}
if (result.Properties.Contains("displayName"))
{
u.DisplayName = result.Properties["displayName"][0].ToString();
}
u.DomainName = getDomainFromDN(u.DistinguishedName);
users.Add(u);
}
}
}
}
}
return users;
}
提前感谢您的帮助。
答案 0 :(得分:3)
您无法使用 memberOf 属性搜索其他林中的群组成员,因为当您将用户添加到本地域时,它无法设置属于另一个森林的群体。
相反,AD会在具有目标用户的SID作为其 CN 的组的域中创建类型为 ForeignSecurityPrincipal 的对象。然后,该对象的 DN 会添加到该群组的成员属性中。
不幸的是,与用户对象不同, foreingSecurityPrincipal 对象永远不会获得 memberOf 属性,因此即使您的搜索也无法找到它们删除 objectType 条件。
因此,您应该按照rufanov的建议反转搜索并枚举群组的成员属性。
但您还应该扩展代码以处理这些外部安全主体。要检测 DirectoryEntry 是否表示外部主体,您可以检查其对象类是否包含 foreignSecurityPricipal 。如果是, CN 属性将包含您可以用来搜索 objectSid 属性的SID
if (de.Properties["objectClass"].Contains("foreignSecurityPrincipal"))
{
// use this value in a search condition for objectSid
var sidString = de.Properties["cn"].Cast<string>().First();
IdentityReference id = new SecurityIdentifier(sid);
var account = id.Translate(typeof(NTAccount)).ToString().Split('\\');
var userName = account[1];
var domainName = account[0];
}
答案 1 :(得分:2)
为什么您不能只枚举目标组的成员,而不是搜索具有目标组作为“memberof”属性值之一的用户的整个林?它比使用DirectorySearcher执行此任务要快得多/简单得多。组“成员”属性是林范围的,因此它将包括来自林中任何域的成员。
获取用户集合的代码可能如下所示:
using System.Collections;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
namespace AdTest
{
class Program
{
static void Main(string[] args)
{
var p = new Program();
var users = p.GetMembersOf("LDAP://CN=SQL Adminsistrators,OU=_System accounts and groups,OU=Domain Users,DC=test,DC=net");
// do something with users
}
private List<User> GetMembersOf(string groupdn)
{
var context = new DirectoryContext(DirectoryContextType.Forest);
var Result = new List<User>();
var GroupEntity = new DirectoryEntry(groupdn);
var Members = (IEnumerable)GroupEntity.Invoke("Members", null);
foreach (var member in Members)
{
var UserEntry = new DirectoryEntry(member);
var User = GetUser(UserEntry);
if(User != null)
Result.Add(User);
}
return Result;
}
private User GetUser(DirectoryEntry UserEntry)
{
var Result = new User();
foreach (PropertyValueCollection UserProperty in UserEntry.Properties)
{
switch (UserProperty.PropertyName)
{
case "sAMAccountName":
Result.UserName = (string)UserProperty.Value;
break;
case "distinguishedName":
Result.DistinguishedName = (string)UserProperty.Value;
Result.DomainName = getDomainFromDN((string)UserProperty.Value);
break;
case "title":
Result.Title = (string)UserProperty.Value;
break;
case "department":
Result.Department = (string)UserProperty.Value;
break;
case "displayName":
Result.DisplayName = (string)UserProperty.Value;
break;
case "objectClass":
var UserClasses = (object[])UserProperty.Value;
if (UserClasses.Contains("user"))
break;
else
return null;
default:
break;
}
}
return Result;
}
private string getDomainFromDN(string p)
{
return string.Empty;
}
public string groupDN { get; set; }
}
}