2010-12-16 2 views
27

Я проверил this сообщение уже. Но это не отвечает на мой вопрос. Я хочу получить все активные группы каталогов, в которых конкретный пользователь является членом.Как получить все группы AD для определенного пользователя?

Я написал следующий код. Но я не могу двигаться дальше, так как не знаю, как дать фильтр и как получить доступ к свойствам.

class Program 
{ 
    static void Main(string[] args) 
    { 
     DirectoryEntry de = new DirectoryEntry("LDAP://mydomain.com"); 
     DirectorySearcher searcher = new DirectorySearcher(de); 
     searcher.Filter = "(&(ObjectClass=group))"; 
     searcher.PropertiesToLoad.Add("distinguishedName"); 
     searcher.PropertiesToLoad.Add("sAMAccountName"); 
     searcher.PropertiesToLoad.Add("name"); 
     searcher.PropertiesToLoad.Add("objectSid"); 
     SearchResultCollection results = searcher.FindAll(); 
     int i = 1; 
     foreach (SearchResult res in results) 
     { 
      Console.WriteLine("Result" + Convert.ToString(i++)); 
      DisplayProperties("distinguishedName", res); 
      DisplayProperties("sAMAccouontName", res); 
      DisplayProperties("name", res); 
      DisplayProperties("objectSid", res); 
      Console.WriteLine(); 
     } 

     Console.ReadKey(); 
    } 

    private static void DisplayProperties(string property, SearchResult res) 
    { 
     Console.WriteLine("\t" + property); 
     ResultPropertyValueCollection col = res.Properties[property]; 
     foreach (object o in col) 
     { 
      Console.WriteLine("\t\t" + o.ToString()); 
     } 
    } 
} 

Любые идеи?

+0

Оки. Я узнал отсюда: http://www.eggheadcafe.com/software/aspnet/30375857/directory-searcher-not-returning-all-groups.aspx, что memberOf не вернет первичные группы пользователей. Но я могу получить primaryGroupID, который дает RID (?) Группы, с помощью которой мне нужно получить группу AD. Есть идеи, как это сделать? – NLV 2010-12-21 05:32:35

+0

Пожалуйста, проверьте мой новый ответ. Ваш нынешний подход работает не очень хорошо. Если пользователю присвоена универсальная группа в другом лесу, Universal Group не будет отображаться в атрибуте memberOf – 2011-01-07 05:03:57

ответ

23

Просто запрос свойства "memberOf" и перебирать, хотя возвращения, например:

  search.PropertiesToLoad.Add("memberOf"); 
      StringBuilder groupNames = new StringBuilder(); //stuff them in | delimited 

       SearchResult result = search.FindOne(); 
       int propertyCount = result.Properties["memberOf"].Count; 
       String dn; 
       int equalsIndex, commaIndex; 

       for (int propertyCounter = 0; propertyCounter < propertyCount; 
        propertyCounter++) 
       { 
        dn = (String)result.Properties["memberOf"][propertyCounter]; 

        equalsIndex = dn.IndexOf("=", 1); 
        commaIndex = dn.IndexOf(",", 1); 
        if (-1 == equalsIndex) 
        { 
         return null; 
        } 
        groupNames.Append(dn.Substring((equalsIndex + 1), 
           (commaIndex - equalsIndex) - 1)); 
        groupNames.Append("|"); 
       } 

      return groupNames.ToString(); 

Это просто общепищевые имена групп в строку groupNames, ограничивают канал, но когда вы вращаетесь, вы можете делать с ними все, что хотите,

18

Использование tokenGroups:

DirectorySearcher ds = new DirectorySearcher(); 
ds.Filter = String.Format("(&(objectClass=user)(sAMAccountName={0}))", username); 
SearchResult sr = ds.FindOne(); 

DirectoryEntry user = sr.GetDirectoryEntry(); 
user.RefreshCache(new string[] { "tokenGroups" }); 

for (int i = 0; i < user.Properties["tokenGroups"].Count; i++) { 
    SecurityIdentifier sid = new SecurityIdentifier((byte[]) user.Properties["tokenGroups"][i], 0); 
    NTAccount nt = (NTAccount)sid.Translate(typeof(NTAccount)); 
    //do something with the SID or name (nt.Value) 
} 

Примечание: это получает только группы безопасности

+2

Этот код был примерно в 10 раз быстрее, чем любой другой код, который я пробовал (используя PrincipalContext). Прошло около 4 секунд, чтобы собрать все группы для пользователя до 400 мс. Благодарю. – Wolf5 2016-12-15 09:43:55

+0

@ Wolf5 Я не понимаю этого, я должен добавить каждый «NTAccount» в список, для каждой итерации? – 2017-06-28 08:05:51

+0

Ну, это работает с использованием списка. Отличный способ, и действительно очень быстро! – 2017-06-28 09:12:47

1

Следующий пример из статьи Код проекта, (Almost) Everything In Active Directory via C#:

// userDn is a Distinguished Name such as: 
// "LDAP://CN=Joe Smith,OU=Sales,OU=domain,OU=com" 
public ArrayList Groups(string userDn, bool recursive) 
{ 
    ArrayList groupMemberships = new ArrayList(); 
    return AttributeValuesMultiString("memberOf", userDn, 
     groupMemberships, recursive); 
} 

public ArrayList AttributeValuesMultiString(string attributeName, 
    string objectDn, ArrayList valuesCollection, bool recursive) 
{ 
    DirectoryEntry ent = new DirectoryEntry(objectDn); 
    PropertyValueCollection ValueCollection = ent.Properties[attributeName]; 
    IEnumerator en = ValueCollection.GetEnumerator(); 

    while (en.MoveNext()) 
    { 
     if (en.Current != null) 
     { 
      if (!valuesCollection.Contains(en.Current.ToString())) 
      { 
       valuesCollection.Add(en.Current.ToString()); 
       if (recursive) 
       { 
        AttributeValuesMultiString(attributeName, "LDAP://" + 
        en.Current.ToString(), valuesCollection, true); 
       } 
      } 
     } 
    } 
    ent.Close(); 
    ent.Dispose(); 
    return valuesCollection; 
} 

Просто вызовите Группы метод с Distinguished Name для пользователя, и передать флаг BOOL, чтобы указать, если вы хотите включить вложенные/дочерние группы членства в вашем результате ArrayList:

ArrayList groups = Groups("LDAP://CN=Joe Smith,OU=Sales,OU=domain,OU=com", true); 
foreach (string groupName in groups) 
{ 
    Console.WriteLine(groupName); 
} 

Если вам нужно сделать какой-либо серьезный уровень программирования Active Directory в .NET Я настоятельно рекомендую отмечать закладкой & г обзор статьи проекта Code, упомянутой выше.

32

Вы должны использовать System.DirectoryServices.AccountManagement. Это намного проще. Вот хороший код проекта article, дающий вам обзор всех классов в этой DLL.

Как вы указали, ваш текущий подход не определяет основную группу. На самом деле, это намного хуже, чем вы думали. Есть еще несколько случаев, когда он не работает, например, локальная группа домена из другого домена. Вы можете проверить here для деталей. Вот как выглядит код, если вы переключитесь на использование System.DirectoryServices.AccountManagement. Следующий код может найти непосредственные группы, которым назначен этот пользователь, который включает основную группу.

UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext (ContextType.Domain, "mydomain.com"), IdentityType.SamAccountName, "username"); 
foreach (GroupPrincipal group in user.GetGroups()) 
{ 
    Console.Out.WriteLine(group); 
} 
0
PrincipalContext pc1 = new PrincipalContext(ContextType.Domain, "DomainName", UserAccountOU, UserName, Password); 
UserPrincipal UserPrincipalID = UserPrincipal.FindByIdentity(pc1, IdentityType.SamAccountName, UserID); 

searcher.Filter = "(&(ObjectClass=group)(member = " + UserPrincipalID.DistinguishedName + ")); 
0

Если у вас есть подключение к LDAP с именем пользователя и пароль для подключения к Active Directory, вот код, который я использовал для подключения правильно:

using System.DirectoryServices.AccountManagement; 

// ... 

// Connection information 
var connectionString = "LDAP://domain.com/DC=domain,DC=com"; 
var connectionUsername = "your_ad_username"; 
var connectionPassword = "your_ad_password"; 

// Get groups for this user 
var username = "myusername"; 

// Split the LDAP Uri 
var uri = new Uri(connectionString); 
var host = uri.Host; 
var container = uri.Segments.Count() >=1 ? uri.Segments[1] : ""; 

// Create context to connect to AD 
var princContext = new PrincipalContext(ContextType.Domain, host, container, connectionUsername, connectionPassword); 

// Get User 
UserPrincipal user = UserPrincipal.FindByIdentity(princContext, IdentityType.SamAccountName, username); 

// Browse user's groups 
foreach (GroupPrincipal group in user.GetGroups()) 
{ 
    Console.Out.WriteLine(group.Name); 
} 
1

Вот код, который работал для меня:

public ArrayList GetBBGroups(WindowsIdentity identity) 
{ 
    ArrayList groups = new ArrayList(); 

    try 
    { 
     String userName = identity.Name; 
     int pos = userName.IndexOf(@"\"); 
     if (pos > 0) userName = userName.Substring(pos + 1); 

     PrincipalContext domain = new PrincipalContext(ContextType.Domain, "riomc.com"); 
     UserPrincipal user = UserPrincipal.FindByIdentity(domain, IdentityType.SamAccountName, userName); 

     DirectoryEntry de = new DirectoryEntry("LDAP://RIOMC.com"); 
     DirectorySearcher search = new DirectorySearcher(de); 
     search.Filter = "(&(objectClass=group)(member=" + user.DistinguishedName + "))"; 
     search.PropertiesToLoad.Add("samaccountname"); 
     search.PropertiesToLoad.Add("cn"); 

     String name; 
     SearchResultCollection results = search.FindAll(); 
     foreach (SearchResult result in results) 
     { 
      name = (String)result.Properties["samaccountname"][0]; 
      if (String.IsNullOrEmpty(name)) 
      { 
       name = (String)result.Properties["cn"][0]; 
      } 
      GetGroupsRecursive(groups, de, name); 
     } 
    } 
    catch 
    { 
     // return an empty list... 
    } 

    return groups; 
} 

public void GetGroupsRecursive(ArrayList groups, DirectoryEntry de, String dn) 
{ 
    DirectorySearcher search = new DirectorySearcher(de); 
    search.Filter = "(&(objectClass=group)(|(samaccountname=" + dn + ")(cn=" + dn + ")))"; 
    search.PropertiesToLoad.Add("memberof"); 

    String group, name; 
    SearchResult result = search.FindOne(); 
    if (result == null) return; 

    group = @"RIOMC\" + dn; 
    if (!groups.Contains(group)) 
    { 
     groups.Add(group); 
    } 
    if (result.Properties["memberof"].Count == 0) return; 
    int equalsIndex, commaIndex; 
    foreach (String dn1 in result.Properties["memberof"]) 
    { 
     equalsIndex = dn1.IndexOf("=", 1); 
     if (equalsIndex > 0) 
     { 
      commaIndex = dn1.IndexOf(",", equalsIndex + 1); 
      name = dn1.Substring(equalsIndex + 1, commaIndex - equalsIndex - 1); 
      GetGroupsRecursive(groups, de, name); 
     } 
    } 
} 

Я измерил его производительность в петле 200 работает против кода, который использует AttributeValuesMultiString рекурсивный метод; и он работал в 1,3 раза быстрее. Возможно, это связано с нашими настройками AD. Оба фрагмента дали тот же результат.

1

Этот код работает даже быстрее (два 1,5 быстрее, чем мои предыдущие версии):

public List<String> GetUserGroups(WindowsIdentity identity) 
    { 
     List<String> groups = new List<String>(); 

     String userName = identity.Name; 
     int pos = userName.IndexOf(@"\"); 
     if (pos > 0) userName = userName.Substring(pos + 1); 

     PrincipalContext domain = new PrincipalContext(ContextType.Domain, "riomc.com"); 
     UserPrincipal user = UserPrincipal.FindByIdentity(domain, IdentityType.SamAccountName, userName); // NGeodakov 

     DirectoryEntry de = new DirectoryEntry("LDAP://RIOMC.com"); 
     DirectorySearcher search = new DirectorySearcher(de); 
     search.Filter = "(&(objectClass=group)(member=" + user.DistinguishedName + "))"; 
     search.PropertiesToLoad.Add("cn"); 
     search.PropertiesToLoad.Add("samaccountname"); 
     search.PropertiesToLoad.Add("memberOf"); 

     SearchResultCollection results = search.FindAll(); 
     foreach (SearchResult sr in results) 
     { 
      GetUserGroupsRecursive(groups, sr, de); 
     } 

     return groups; 
    } 

    public void GetUserGroupsRecursive(List<String> groups, SearchResult sr, DirectoryEntry de) 
    { 
     if (sr == null) return; 

     String group = (String)sr.Properties["cn"][0]; 
     if (String.IsNullOrEmpty(group)) 
     { 
      group = (String)sr.Properties["samaccountname"][0]; 
     } 
     if (!groups.Contains(group)) 
     { 
      groups.Add(group); 
     } 

     DirectorySearcher search; 
     SearchResult sr1; 
     String name; 
     int equalsIndex, commaIndex; 
     foreach (String dn in sr.Properties["memberof"]) 
     { 
      equalsIndex = dn.IndexOf("=", 1); 
      if (equalsIndex > 0) 
      { 
       commaIndex = dn.IndexOf(",", equalsIndex + 1); 
       name = dn.Substring(equalsIndex + 1, commaIndex - equalsIndex - 1); 

       search = new DirectorySearcher(de); 
       search.Filter = "(&(objectClass=group)(|(cn=" + name + ")(samaccountname=" + name + ")))"; 
       search.PropertiesToLoad.Add("cn"); 
       search.PropertiesToLoad.Add("samaccountname"); 
       search.PropertiesToLoad.Add("memberOf"); 
       sr1 = search.FindOne(); 
       GetUserGroupsRecursive(groups, sr1, de); 
      } 
     } 
    } 
Смежные вопросы