2010-11-22 10 views
20

मुझे पता है कि इस प्रकार के प्रश्न से पहले पूछा गया है, लेकिन अन्य विधियां अभी मुझे विफल कर रही हैं।सी # सक्रिय निर्देशिका: उपयोगकर्ता का डोमेन नाम प्राप्त करें?

चूंकि यह हमारे विंडोज सेवा चुनाव एडी है, एलडीएपी (यानी एलडीएपी: //10.32.16.80) और उस विज्ञापन सर्वर के भीतर उपयोगकर्ता समूह की एक सूची दी गई है। यह उन समूहों के भीतर सभी उपयोगकर्ताओं को पुनर्प्राप्त करता है, जो उन समूहों को अधिक समूहों के लिए खोजते हैं। प्रत्येक उपयोगकर्ता को तब अन्य उपयोगकर्ताओं को प्रमाणित उपयोगकर्ता सूची में जोड़ा जाता है।

एप्लिकेशन का यह हिस्सा सफलतापूर्वक चल रहा है। हालांकि, हमें प्रत्येक उपयोगकर्ता के अनुकूल डोमेन नाम (यानी उनके लॉगिन डोमेन/उपयोगकर्ता नाम का हिस्सा) की आवश्यकता है

तो यदि कोई उपयोगकर्ता है जो टेस्ट डोमेन का हिस्सा है, स्टीव: टेस्ट/स्टीव उसका लॉगिन है । मैं एडी में स्टीव ढूंढने में सक्षम हूं, हालांकि मुझे अपनी एडी जानकारी के साथ "टेस्ट" स्टोर करने की भी आवश्यकता है।

फिर से, मुझे एक निर्देशिका खोजकर्ता और एलडीएपी आईपी का उपयोग करके 'स्टीव' जुर्माना मिल सकता है, लेकिन एलडीएपी आईपी दिया गया है, मैं दोस्ताना डोमेन नाम कैसे प्राप्त कर सकता हूं?

जब मैं निम्नलिखित कोड जब 'defaultNamingContext' तक पहुँचने का प्रयास करने पर मुझे त्रुटि दिया हूँ कोशिश:

System.Runtime.InteropServices.COMException (0x8007202A): प्रमाणीकरण तंत्र अज्ञात है।

private string SetCurrentDomain(string server) 
    { 
     string result = string.Empty; 
     try 
     { 
      logger.Debug("'SetCurrentDomain'; Instantiating rootDSE LDAP"); 
      DirectoryEntry ldapRoot = new DirectoryEntry(server + "/rootDSE", username, password); 
      logger.Debug("'SetCurrentDomain'; Successfully instantiated rootDSE LDAP"); 

      logger.Debug("Attempting to retrieve 'defaultNamingContext'..."); 
      string domain = (string)ldapRoot.Properties["defaultNamingContext"][0]; //THIS IS WHERE I HIT THE COMEXCEPTION 
      logger.Debug("Retrieved 'defaultNamingContext': " + domain); 
      if (!domain.IsEmpty()) 
      { 

       logger.Debug("'SetCurrentDomain'; Instantiating partitions/configuration LDAP entry"); 
       DirectoryEntry parts = new DirectoryEntry(server + "/CN=Partitions,CN=Configuration," + domain, username, password); 

       logger.Debug("'SetCurrentDomain'; Successfully instantiated partitions/configuration LDAP entry"); 
       foreach (DirectoryEntry part in parts.Children) 
       { 
        if (part.Properties["nCName"] != null && (string)part.Properties["nCName"][0] != null) 
        { 
         logger.Debug("'SetCurrentDomain'; Found property nCName"); 
         if ((string)part.Properties["nCName"][0] == domain) 
         { 
          logger.Debug("'SetCurrentDomain'; nCName matched defaultnamingcontext"); 
          result = (string)part.Properties["NetBIOSName"][0]; 
          logger.Debug("'SetCurrentDomain'; Found NetBIOSName (friendly domain name): " + result); 
          break; 
         } 
        } 
       } 
      } 
      logger.Debug("finished setting current domain..."); 
     } 
     catch (Exception ex) 
     { 
      logger.Error("error attempting to set domain:" + ex.ToString()); 
     } 
     return result; 
    } 

संपादित

मैं आदेश एक सुझाव प्रयास करने के लिए, लेकिन एक अपवाद हो रही है में इस नमूने विधि कहा:: जब मैं "FindAll हिट" अनिर्दिष्ट त्रुटि "

यहाँ कोड है() "खोजकर्ता पर कॉल करें। स्ट्रिंग में पारित किया जा रहा है: "सीएन = जांच उपयोगकर्ता, सीएन = उपयोगकर्ता, डीसी = Tempe, डीसी = ktregression, डीसी = कॉम"

 private string GetUserDomain(string dn) 
    { 
     string domain = string.Empty; 
     string firstPart = dn.Substring(dn.IndexOf("DC=")); 
     string secondPart = "CN=Partitions,CN=Configuration," + firstPart; 
     DirectoryEntry root = new DirectoryEntry(secondPart, textBox2.Text, textBox3.Text); 
     DirectorySearcher searcher = new DirectorySearcher(root); 
     searcher.SearchScope = SearchScope.Subtree; 
     searcher.ReferralChasing = ReferralChasingOption.All; 
     searcher.Filter = "(&(nCName=" + firstPart + ")(nETBIOSName=*))"; 
     try 
     { 
      SearchResultCollection rs = searcher.FindAll(); 
      if (rs != null) 
      { 
       domain = GetProperty(rs[0], "nETBIOSName"); 
      } 
     } 
     catch (Exception ex) 
     { 

     } 


     return domain; 
+0

क्या वर्तमान डोमेन के समान वन के अंतर्गत 'टेस्ट' डोमेन है? यदि ऐसा है, तो आप इस उपयोगकर्ता के लिए सही डोमेन से पूछ सकते हैं, क्योंकि उपयोगकर्ता आपके वर्तमान डोमेन में मौजूद हो सकता है, लेकिन दूसरे में नहीं। –

+0

हां, टेस्ट डोमेन वर्तमान डोमेन के समान वन में होगा। उस संबंध में, मैं किसी दिए गए उपयोगकर्ता के लिए डोमेन से पूछताछ के बारे में कैसे जा सकता हूं? ध्यान रखें कि मेरा एडी ज्ञान सीमित है, इसमें मुझे एलडीएपी तारों और इस तरह के निर्माण पर अच्छी तरह से जानकारी नहीं है ... –

+0

संभावित डुप्लिकेट [एनटी शैली डोमेन \ उपयोगकर्ता को डीएन प्राप्त करें] प्राप्त करें (http://stackoverflow.com/ प्रश्न/17 9 6426/get-nt-style-domain-user-given-dn) - यह उपयोगकर्ता के डीएन को अपने नेटबीओएस डोमेन नाम में कनवर्ट करने के बारे में जानकारी प्रदान करता है, जो आप यहां चाहते हैं। –

उत्तर

25

यह लेख मुझे बहुत समझने के लिए सक्रिय के साथ काम करने में मदद की निर्देशिका।
Howto: (Almost) Everything In Active Directory via C#

इस बिंदु आगे से, अगर आप आगे में सहायता की आवश्यकता होती है, मुझे टिप्पणी में उचित सवालों के साथ हमें बताएं, और मैं अपने ज्ञान के अनुसार आप के लिए उनका जवाब होगा।

संपादित करें # 1

बेहतर होगा कि तुम बजाय इस उदाहरण के फिल्टर के साथ जाना था। मैंने संक्षेप में यह दिखाने के लिए कुछ नमूना कोड लिखा है कि System.DirectoryServices और System.DirectoryServices.ActiveDirectory नामस्थानों के साथ कैसे काम करना है। System.DirectoryServices.ActiveDirectory नामस्थान का उपयोग आपके वन के डोमेन के बारे में जानकारी पुनर्प्राप्त करने के लिए किया जाता है।

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

यहां, मैंने इस कोड का परीक्षण नहीं किया है और इसे ठीक करने के लिए कुछ मामूली समस्या हो सकती है। यह नमूना आपकी मदद करने के लिए प्रदान किया गया है। मुझे उम्मीद है कि इससे सहायता मिलेगी।

संपादित करें # 2

मैं बाहर एक और तरीका पता चला:

  1. आप आप अपने डोमेन के भीतर उपयोगकर्ता खाते पा सकते हैं कि क्या देखने के लिए पहले है;
  2. यदि मिला, तो डोमेन नेटबीओएसओ नाम प्राप्त करें; और
  3. इसे बैकस्लैश (****) और पाए गए लॉगिन में जोड़ दें।

नीचे दिए गए उदाहरण एक NUnit testcase जो आप खुद के लिए परीक्षण करने और अगर यह होता है कि आप क्या करने की आवश्यकता है देख सकते हैं का उपयोग करता है।

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

स्रोत है जहाँ से मैं अपने आप को प्रेरित है:
Find the NetBios Name of a domain in AD

+0

क्या, मैंने उस साइट को कई बार उपयोग किया है, लेकिन ऐसा लगता है कि इस सवाल पर कोई विशिष्ट जानकारी नहीं दी गई है। हालांकि धन्यवाद। –

+0

@Micheal Velasquez: कृपया कोड कोड के लिए मेरा संपादन देखें, जो मुझे आशा है, आपकी मदद करेगा। –

+0

मैंने आपके कोड नमूना को मेरे सी # टेस्ट ऐप पर और कुछ tweaks (यानी GetDomains() विधि, आदि का रिटर्न प्रकार) पर पोर्ट किया है। मैं GetUserDomain() विधि की उपज वापसी के साथ किसी समस्या में भाग रहा हूं। DirectoryEntry ऑब्जेक्ट "डोमेन" में कोई संपत्ति "डोमेन" नहीं है (यानी डोमेन.डोमेन) –

3

आप डोमेन कि वर्तमान उपयोगकर्ता Environment.UserDomainName Property के प्रयोग पर है के नाम पर प्राप्त कर सकते हैं।

string domainName; 
domainName = System.Environment.UserDomainName; 
+2

सुझाएं यदि मैं किसी निर्दिष्ट उपयोगकर्ता का डोमेन नाम प्राप्त करना चाहता हूं तो क्या होगा? – SearchForKnowledge

4

चूंकि मुझे कोई उदाहरण कोड नहीं मिला क्योंकि मैं अपना स्वयं का समाधान साझा करना चाहता हूं। यह DirectoryEntry ऑब्जेक्ट के माता-पिता को तब तक खोजेगा जब तक वह डोमेन डीएनएस कक्षा को हिट नहीं करता।

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

इस तरह यह प्रयोग करें:

string[] _properties = new string[] { "objectClass", "distinguishedName", "samAccountName", "userPrincipalName", "displayName", "mail", "title", "company", "thumbnailPhoto", "useraccountcontrol" }; 
string account = "my-user-name"; 
// OR even better: 
// string account = "[email protected]"; 

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

मैं इस पर परीक्षण करने के लिए एक जंगल नहीं मिला है, लेकिन सिद्धांत रूप में यह कटौती करनी चाहिए।

+0

यह अच्छी तरह से काम करता है लेकिन वहाँ 'ldap_get_value' के लिए एक और अधिक सुरुचिपूर्ण कार्यान्वयन है:' entry.Properties [प्रॉपर्टी] .OfType (वापसी) .LastOrDefault(); ' –

+0

धन्यवाद Tiele, अपने कोड छोटे परिवर्तन के साथ मेरे लिए काम करता है, लेकिन यह लग रहा है मुझे ऑनलाइन मिले अन्य कोड की तुलना में बहुत तेज़। –

+0

मैं var 'user = searcher.FindOne()। GetDirectoryEntry();' line में "उपयोगकर्ता नाम या पासवर्ड गलत है" अपवाद प्राप्त कर रहा हूं। क्या यह प्रमाणीकरण त्रुटि है? – Shesha

1

हो सकता है कि पूरी तरह से सही नहीं है, लेकिन ...

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

क्योंकि de.Path का मूल्य

एलडीएपी है: // सीएन = FullName, डीसी = डोमेन, डीसी = स्थानीय

+0

कम नेटवर्क होप्स के साथ मेरे लिए काम करता है। शायद सभी के लिए काम नहीं करेगा क्योंकि उनको 1-से-1 होना जरूरी नहीं है, मैं नहीं जानता हूं –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^