C# Active Directory: Get domain name of user?

前端 未结 4 390
难免孤独
难免孤独 2020-12-02 13:43

I know that this type of question has been asked before, but other methods are failing me right now.

As it stands our windows service polls AD, given an LDAP (i.e. L

相关标签:
4条回答
  • 2020-12-02 13:59

    You can retrieve the name of the domain that the current user is on using the Environment.UserDomainName Property.

    string domainName;
    domainName = System.Environment.UserDomainName;
    
    0 讨论(0)
  • 2020-12-02 14:01

    This article helped me much to understand how to work with the Active Directory.
    Howto: (Almost) Everything In Active Directory via C#

    From this point forward, if you require further assitance, please let me know with proper questions in comment, and I shall answer them for you to the best of my knowledge.

    EDIT #1

    You had better go with this example's filter instead. I have written some sample code to briefly show how to work with the System.DirectoryServices and System.DirectoryServices.ActiveDirectory namespaces. The System.DirectoryServices.ActiveDirectory namespace is used to retrieve information about the domains within your Forest.

    private IEnumerable<DirectoryEntry> GetDomains() {
        ICollection<string> domains = new List<string>();
    
        // Querying the current Forest for the domains within.
        foreach(Domain d in Forest.GetCurrentForest().Domains)
            domains.Add(d.Name);
    
        return domains;
    }
    
    private string GetDomainFullName(string friendlyName) {
        DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, friendlyName);
        Domain domain = Domain.GetDomain(context);
        return domain.Name;
    }
    
    private IEnumerable<string> GetUserDomain(string userName) {
        foreach(string d in GetDomains()) 
            // From the domains obtained from the Forest, we search the domain subtree for the given userName.
            using (DirectoryEntry domain = new DirectoryEntry(GetDomainFullName(d))) {
                using (DirectorySearcher searcher = new DirectorySearcher()){
                    searcher.SearchRoot = domain;
                    searcher.SearchScope = SearchScope.Subtree;
                    searcher.PropertiesToLoad.Add("sAMAccountName");
                    // The Filter is very important, so is its query string. The 'objectClass' parameter is mandatory.
                    // Once we specified the 'objectClass', we want to look for the user whose login
                    // login is userName.
                    searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", userName);
    
                    try {
                        SearchResultCollection  results = searcher.FindAll();
    
                        // If the user cannot be found, then let's check next domain.
                        if (results == null || results.Count = 0)
                            continue;
    
                         // Here, we yield return for we want all of the domain which this userName is authenticated.
                         yield return domain.Path;
                    } finally {
                        searcher.Dispose();
                        domain.Dispose();
                    }
                }
    }
    

    Here, I didn't test this code and might have some minor issue to fix. This sample is provided as-is for the sake of helping you. I hope this will help.

    EDIT #2

    I found out another way out:

    1. You have first to look whether you can find the user account within your domain;
    2. If found, then get the domain NetBIOS Name; and
    3. concatenate it to a backslash (****) and the found login.

    The example below uses a NUnit TestCase which you can test for yourself and see if it does what you are required to.

    [TestCase("LDAP://fully.qualified.domain.name", "TestUser1")] 
    public void GetNetBiosName(string ldapUrl, string login)
        string netBiosName = null;
        string foundLogin = null;
    
        using (DirectoryEntry root = new DirectoryEntry(ldapUrl))
            Using (DirectorySearcher searcher = new DirectorySearcher(root) {
                searcher.SearchScope = SearchScope.Subtree;
                searcher.PropertiesToLoad.Add("sAMAccountName");
                searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", login);
    
                SearchResult result = null;
    
                try {
                    result = searcher.FindOne();
    
                    if (result == null) 
                        if (string.Equals(login, result.GetDirectoryEntry().Properties("sAMAccountName").Value)) 
                            foundLogin = result.GetDirectoryEntry().Properties("sAMAccountName").Value
                } finally {
                    searcher.Dispose();
                    root.Dispose();
                    if (result != null) result = null;
                }
            }
    
        if (!string.IsNullOrEmpty(foundLogin)) 
            using (DirectoryEntry root = new DirectoryEntry(ldapUrl.Insert(7, "CN=Partitions,CN=Configuration,DC=").Replace(".", ",DC=")) 
                Using DirectorySearcher searcher = new DirectorySearcher(root)
                    searcher.Filter = "nETBIOSName=*";
                    searcher.PropertiesToLoad.Add("cn");
    
                    SearchResultCollection results = null;
    
                    try {
                        results = searcher.FindAll();
    
                        if (results != null && results.Count > 0 && results[0] != null) {
                            ResultPropertyValueCollection values = results[0].Properties("cn");
                            netBiosName = rpvc[0].ToString();
                    } finally {
                        searcher.Dispose();
                        root.Dispose();
    
                        if (results != null) {
                            results.Dispose();
                            results = null;
                        }
                    }
                }
    
        Assert.AreEqual("FULLY\TESTUSER1", string.Concat(netBiosName, "\", foundLogin).ToUpperInvariant())
    }
    

    The source from which I inspired myself is:
    Find the NetBios Name of a domain in AD

    0 讨论(0)
  • 2020-12-02 14:07

    Maybe not entirely correct but...

    DirectoryEntry dirEntry = new DirectoryEntry();         
    DirectorySearcher dirSearcher = new DirectorySearcher(dirEntry);
    dirSearcher.SearchScope = SearchScope.Subtree;
    dirSearcher.Filter = string.Format("(&(objectClass=user)(|(cn={0})(sn={0}*)(givenName={0})(sAMAccountName={0}*)))", userName);
    var searchResults = dirSearcher.FindAll();
    
    foreach (SearchResult sr in searchResults)
    {
         var de = sr.GetDirectoryEntry();
         string user = de.Properties["SAMAccountName"][0].ToString();               
         string domain = de.Path.ToString().Split(new [] { ",DC=" },StringSplitOptions.None)[1];
         MessageBox.Show(domain + "/" + user);
    }
    

    Because the value of de.Path is

    LDAP://CN=FullName,DC=domain,DC=local

    0 讨论(0)
  • 2020-12-02 14:21

    Since I could not find any example code I would like to share my own solution. This will search the parents of the DirectoryEntry object until it hits the domainDNS class.

    using System.DirectoryServices;
    
    public static class Methods
    {
        public static T ldap_get_value<T>(PropertyValueCollection property)
        {
            object value = null;
            foreach (object tmpValue in property) value = tmpValue;
            return (T)value;
        }
    
        public static string ldap_get_domainname(DirectoryEntry entry)
        {
            if (entry == null || entry.Parent == null) return null;
            using (DirectoryEntry parent = entry.Parent)
            {
                if (ldap_get_value<string>(parent.Properties["objectClass"]) == "domainDNS") 
                    return ldap_get_value<string>(parent.Properties["dc"]);
                else 
                    return ldap_get_domainname(parent);
            }
        }
    }
    

    Use it like this:

    string[] _properties = new string[] { "objectClass", "distinguishedName", "samAccountName", "userPrincipalName", "displayName", "mail", "title", "company", "thumbnailPhoto", "useraccountcontrol" };
    string account = "my-user-name";
    // OR even better:
    // string account = "my-user-name@DOMAIN.local";
    
    using (DirectoryEntry ldap = new DirectoryEntry())
    {
        using (DirectorySearcher searcher = new DirectorySearcher(ldap))
        {
            searcher.PropertiesToLoad.AddRange(_properties);
            if (account.Contains('@')) searcher.Filter = "(userPrincipalName=" + account + ")";
            else searcher.Filter = "(samAccountName=" + account + ")";
            var user = searcher.FindOne().GetDirectoryEntry();
    
            Console.WriteLine("Name: " + Methods.ldap_get_value<string>(user.Properties["displayName"]));
            Console.WriteLine("Domain: " + Methods.ldap_get_domainname(user));
            Console.WriteLine("Login: " + Methods.ldap_get_domainname(user) + "\\" + Methods.ldap_get_value<string>(user.Properties["samAccountName"]));
        }
    }
    

    I haven't got a forest to test it on but in theory this should cut it.

    0 讨论(0)
提交回复
热议问题