it-swarm.com.de

Wie bekomme ich alle AD-Gruppen für einen bestimmten Benutzer?

Ich habe das bereits geprüft. Aber es beantwortet meine Frage nicht. Ich möchte alle Active Directory-Gruppen abrufen, in denen ein bestimmter Benutzer Mitglied ist.

Ich habe den folgenden Code geschrieben. Ich kann jedoch nicht weiter fortfahren, da ich nicht weiß, wie ich den Filter vergeben und wie ich auf die Eigenschaften zugreifen kann.

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());
        }
    }
}

Irgendwelche Ideen?

33
NLV

Fragen Sie einfach die "memberOf" -Eigenschaft ab und durchlaufen Sie die Rückgabe, Beispiel:

            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();

Dies fügt die Gruppennamen einfach in die Zeichenfolge groupNames (getrennt durch Pipe) ein. Wenn Sie jedoch durchlaufen, können Sie mit ihnen alles tun, was Sie möchten

25
curtisk

Sie sollten System.DirectoryServices.AccountManagement verwenden. Es ist viel einfacher. Hier ist ein Nice-Code-Projekt article , das einen Überblick über alle Klassen in dieser DLL gibt.

Wie Sie bereits gesagt haben, ermittelt Ihr aktueller Ansatz nicht die Primärgruppe. Eigentlich ist es viel schlimmer als Sie gedacht haben. Es gibt einige weitere Fälle, in denen dies nicht funktioniert, z. B. die lokale Gruppe der Domänen einer anderen Domäne. Sie können hier für Details überprüfen. So sieht der Code aus, wenn Sie zur Verwendung von System.DirectoryServices.AccountManagement wechseln. Der folgende Code kann die unmittelbaren Gruppen finden, denen dieser Benutzer zugewiesen ist, einschließlich der primären Gruppe.

UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext (ContextType.Domain, "mydomain.com"), IdentityType.SamAccountName, "username");
foreach (GroupPrincipal group in user.GetGroups())
{
    Console.Out.WriteLine(group);
}
35
Harvey Kwok

Verwenden Sie 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)
}

Hinweis: Dadurch werden nur Sicherheitsgruppen abgerufen

23
Shurdoof

Das folgende Beispiel stammt aus dem Code Project-Artikel (fast) alles in Active Directory über 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;
}

Rufen Sie einfach die Groups -Methode mit Distinguished Name für den Benutzer auf und übergeben Sie das Bool-Flag, um anzugeben, ob Sie verschachtelte/untergeordnete Gruppenmitgliedschaften in die resultierende ArrayList aufnehmen möchten:

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

Wenn Sie eine ernstzunehmende Version der Active Directory-Programmierung in .NET durchführen möchten, empfehle ich Ihnen dringend, das oben erwähnte Artikel für Code Project zu markieren und zu lesen.

2
Saul Dolgin

So liste ich alle Gruppen (direkt und indirekt) für einen bestimmten Distinguished Name auf:

Die Zeichenfolge 1.2.840.113556.1.4.1941 gibt LDAP_MATCHING_RULE_IN_CHAIN ​​an. 

Diese Regel ist auf Filter beschränkt, die für den DN gelten. Dies ist ein spezieller "erweiterter" Übereinstimmungsoperator, der die Vorfahrenkette in Objekten bis zum Stamm durchläuft, bis er eine Übereinstimmung findet.

Diese Methode ist 25 Mal schneller als die Methode UserPrincipal.GetGroups () in meinem Test.

Anmerkung: Die primäre Gruppe (normalerweise Domänenbenutzer) wird von dieser oder der GetGroups () -Methode nicht zurückgegeben. Um auch den primären Gruppennamen zu erhalten, habe ich diese Methode funktioniert bestätigt. 

Außerdem fand ich diese Liste von LDAP Filtern äußerst nützlich.

private IEnumerable<string> GetGroupsForDistinguishedName(DirectoryEntry domainDirectoryEntry, string distinguishedName)
{
    var groups = new List<string>();
    if (!string.IsNullOrEmpty(distinguishedName))
    {
        var getGroupsFilterForDn = $"(member:1.2.840.113556.1.4.1941:={distinguishedName})";
        using (var dirSearch = CreateDirectorySearcher(domainDirectoryEntry, getGroupsFilterForDn))
        {
            dirSearch.PropertiesToLoad.Add("name");

            using (var results = dirSearch.FindAll())
            {
                foreach (SearchResult result in results)
                {
                    if (result.Properties.Contains("name"))
                        groups.Add((string)result.Properties["name"][0]);
                }
            }
        }
    }

    return groups;
}
2
noctural

Dieser Code arbeitet noch schneller (zwei 1,5-mal schneller als meine vorherige Version):

    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);
            }
        }
    }
2
Nuren Geodakov

Hier ist der Code, der für mich funktioniert hat:

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);
        }
    }
}

Ich habe die Leistung in einer Schleife von 200 Läufen gegen den Code gemessen, der die rekursive Methode AttributeValuesMultiString verwendet. und es funktionierte um das 1,3-fache schneller ... __ Möglicherweise aufgrund unserer AD-Einstellungen. Beide Ausschnitte gaben das gleiche Ergebnis.

1
Nuren Geodakov

Ich möchte sagen, dass Microsoft LDAP einige spezielle Möglichkeiten hat, rekursiv nach allen Mitgliedschaften eines Benutzers zu suchen.

  1. Die Übereinstimmungsregel, die Sie für das Attribut "Mitglied" angeben können. Die Verwendung der Microsoft Exclusive LDAP_MATCHING_RULE_IN_CHAIN ​​ - Regel für das "member" -Attribut ermöglicht die rekursive/verschachtelte Mitgliedschaftssuche. Die Regel wird verwendet, wenn Sie sie nach dem Member-Attribut hinzufügen. Ex. (Mitglied: 1.2.840.113556.1.4.1941: = XXXXX)

  2. Für dieselbe Domäne wie das Konto kann der Filter anstelle eines Attributs "Accounts DistinguishedName" <SID = S-1-5-21-XXXXXXXXXXXXXXXXXXXXX> verwenden, was bei Bedarf sehr nützlich ist, um die domänenübergreifende Verwendung zu ermöglichen. Es scheint jedoch, als müssten Sie ForeignSecurityPrincipal <GUID = YYYY> verwenden, da Ihre SID nicht aufgelöst wird, da das Tag <SID => den Objekttyp ForeignSecurityPrincipal nicht berücksichtigt. Sie können auch den ForeignSecurityPrincipal DistinguishedName verwenden.

Mit diesem Wissen können Sie LDAP-Abfragen der schwer zu erreichenden Mitgliedschaften abfragen, z. B. der Gruppe "Lokale Domäne", in der ein Konto Mitglied ist. Wenn Sie sich jedoch nicht die Mitglieder der Gruppe angesehen haben, wissen Sie nicht, ob der Benutzer Mitglied ist.

//Get Direct+Indirect Memberships of User (where SID is XXXXXX)

string str = "(& (objectCategory=group)(member:1.2.840.113556.1.4.1941:=<SID=XXXXXX>) )";

//Get Direct+Indirect **Domain Local** Memberships of User (where SID is XXXXXX)

string str2 = "(& (objectCategory=group)(|(groupType=-2147483644)(groupType=4))(member:1.2.840.113556.1.4.1941:=<SID=XXXXXX>) )";

//TAA DAA



Fühlen Sie sich frei, diese LDAP-Abfragen zu testen, nachdem Sie die SID eines Benutzers ersetzt haben, für den Sie alle Gruppenmitgliedschaften abrufen möchten. Ich denke, dies ist ähnlich, wenn nicht dieselbe Abfrage wie der PowerShell-Befehl Get-ADPrincipalGroupMembership hinter den Kulissen verwendet wird. Der Befehl besagt "Wenn Sie nach lokalen Gruppen in einer anderen Domäne suchen möchten, verwenden Sie den Parameter ResourceContextServer, um den alternativen Server in der anderen Domäne anzugeben."

Wenn Sie mit C # und Active Directory vertraut sind, sollten Sie wissen, wie Sie eine LDAP-Suche mit den bereitgestellten LDAP-Abfragen durchführen.

Zusätzliche Dokumentation: 

1
C Sharp Conner

Wenn Sie über eine LDAP-Verbindung mit einem Benutzernamen und einem Kennwort verfügen, um eine Verbindung zu Active Directory herzustellen, finden Sie hier den Code, den ich für die korrekte Verbindung verwendet habe:

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);
}
0
Maxime