2009-05-05 9 views
18

मैं यह पता लगाने की कोशिश कर रहा हूं कि सक्रिय निर्देशिका उपयोगकर्ता और कंप्यूटर उपकरण में "उपयोगकर्ता, संपर्क और समूह" कैसे काम करते हैं, इस तरह सी # से एडी को कैसे खोजा जाए। मेरे पास एक स्ट्रिंग है जिसमें या तो समूह का नाम है, या उपयोगकर्ता का नाम (आमतौर पर प्रारूप में प्रथम नाम मध्यस्थ [यदि उनके पास एक है] अंतिम नाम है, लेकिन हमेशा नहीं)। यहां तक ​​कि यदि मैं समूह बनाम उपयोगकर्ताओं के लिए एक अलग क्वेरी करता हूं, तो मैं खोज के लिए एक रास्ता नहीं आ सकता हूं जो अधिकतर उपयोगकर्ता खातों को कैप्चर करता है। उपयोगकर्ता, संपर्क, और समूह उपकरण खोजें उन्हें लगभग हर बार वापस लाता है। किसी के पास कोई सुझाव है?आप सी # से सक्रिय निर्देशिका में उपयोगकर्ता कैसे ढूंढ सकते हैं?

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

+0

नीचे जवाब पढ़ें सब के बारे में sAMAccountName का उपयोग कर, और मैं नहीं जानता कि क्यों वे इतने सारे upvotes है कर रहे हैं: यही कारण है कि है। यह प्रश्न गुण प्राप्त करने के लिए पहले और अंतिम नाम का उपयोग करने के बारे में है! केवल शीर्ष/चिह्नित सही उत्तर भी करीब है। – vapcguy

उत्तर

18

नेट 3 पर आप कर रहे हैं लागू करने के लिए .5? यदि ऐसा है - एडी 3.5 में बहुत अच्छी नई विशेषताएं हैं - इस लेख को Managing Directory Security Principals in .NET 3.5 एथन विल्स्की और जो कपलन द्वारा देखें।

बड़ी नई सुविधाओं में से एक "प्रिंसिपलशियर" वर्ग है जिसे एडी में उपयोगकर्ताओं और/या समूहों को खोजने में बहुत सरलता होनी चाहिए।

यदि आप .NET 3.5 का उपयोग नहीं कर सकते हैं, तो एक चीज जो आपके जीवन को आसान बना सकती है उसे "अस्पष्ट नाम समाधान" कहा जाता है, और यह एक छोटा ज्ञात विशेष खोज फ़िल्टर है जो किसी भी नाम से संबंधित विशेषता में एक बार में खोज करेगा ।

निर्दिष्ट इस तरह अपने LDAP खोज क्वेरी:

searcher.Filter = string.Format("(&(objectCategory=person)(anr={0}))", yourSearchTerm) 

इसके अलावा, मैं, "objectCategory" विशेषता पर छानने की सिफारिश करेंगे के बाद से है कि एकल-मान और ईस्वी में डिफ़ॉल्ट रूप से अनुक्रमित है, जो एक बहुत तेजी से है "objectClass" का उपयोग कर।

मार्क

+0

यह वही है जो मैं ढूंढ रहा था! आपका बहुत बहुत धन्यवाद! – Sunookitsune

10

सिस्टम। निर्देशिका सेवा में दो नामस्थान हैं ... DirectoryEntry और DirectorySearcher। DirectorySearcher यहाँ पर

और जानकारी:

http://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher.aspx

फिर आप समूह, उपयोगकर्ता आदि के आधार पर फ़िल्टर करने के लिए फ़िल्टर संपत्ति का उपयोग कर सकते हैं ...

तो अगर आप खाते के नाम के आधार पर फ़िल्टर करना चाहता था आप फ़िल्टर को सेट करेंगे:

"(&(sAMAccountName=bsmith))" 

और फ़िल्टरएल विधि चलाएं। यह एक SearchResultCollection वापस करेगा जो आप उपयोगकर्ता के बारे में जानकारी खींच सकते हैं और खींच सकते हैं।

+0

धन्यवाद, हालांकि मैं DirectorySearcher के बारे में जानता हूं। मुद्दा यह है कि मैं एडी में उपयोगकर्ताओं को खोजने के लिए एक प्रश्न के साथ नहीं आ सकता। – Sunookitsune

+0

@Sunookitsune - तो आप सटीक कार्यक्षमता को दोहराने की कोशिश कर रहे हैं "उपयोगकर्ता, संपर्क, और समूह खोजें"? –

+0

@ मियागी कोडर मैं बिल्कुल उस कार्यक्षमता को नहीं कहूंगा, लेकिन कम से कम कुछ लोगों के लिए यह खोजता है कि यह कैसे खोजता है। या कुछ और ढूंढें जो काम करेगा, क्योंकि मैं स्टंप हूं। – Sunookitsune

4

आपको उपयोगकर्ता की तलाश करने के तरीके पर आधारित खोज स्ट्रिंग बनाने की आवश्यकता है।

using (var adFolderObject = new DirectoryEntry()) 
{ 
    using(var adSearcherObject = new DirectorySearcher(adFolderObject)) 
    { 
      adSearcherObject.SearchScope = SearchScope.Subtree; 
      adSearcherObject.Filter = "(&(objectClass=person)(" + userType + "=" + userName + "))"; 

      return adSearcherObject.FindOne(); 
    } 
} 

उपयोगकर्ता टाइप या तो उपयोगकर्ता नाम स्वरूपित करने के आधार पर sAMAccountName या CN होना चाहिए।

पूर्व:
firstname.lastname (या flastname) आम तौर पर sAMAccountName हो जाएगा
प्रथम नाम अंतिम नाम आमतौर पर सीएन

+0

के लिए +1 नहीं, 'sAMAccountName' उपयोगकर्ता नाम है, यानी जॉन डो के लिए' doej', और ओपी के पास उपयोगकर्ता का नाम नहीं है। यदि आप 'उपयोगकर्ता टाइप' के लिए 'सीएन' का उपयोग करने के लिए कह रहे हैं और' उपयोगकर्ता नाम 'के बजाय' फर्स्टनाम अंतिम नाम 'में डालते हैं, तो वास्तव में फ़िल्टर' '(& (objectCategory = user) (objectClass = user) (objectClass = user) का उपयोग करना बेहतर होगा (दिया गया नाम = "+ firstName +") (sn = "+ lastName +")) "; 'इसके बजाए। – vapcguy

2

मियागी के जवाब पर जोड़ने के लिए किया जाएगा ....

यहां फ़िल्टर है/क्वेरी DirectorySearcher को

DirectorySearcher ds = new DirectorySearcher(); 

ds.Filter = "samaccountname=" + userName; 

SearchResult result = ds.FindOne(); 
+0

बोनज़ाई कर्टिस !!!! –

+0

ओपी में उपयोगकर्ता नाम नहीं था, यानी जॉन डो के लिए 'DOMAIN \ doej' - वह इसके बजाय पहला और अंतिम नाम प्राप्त करता है। यह फ़िल्टर इसके लिए बेकार है। – vapcguy

3
public DirectoryEntry Search(string searchTerm, string propertyName) 
{ 
    DirectoryEntry directoryObject = new DirectoryEntry(<pathToAD>); 

    foreach (DirectoryEntry user in directoryObject.Children) 
    { 
     if (user.Properties[propertyName].Value != null)  
     if (user.Properties[propertyName].Value.ToString() == searchTerm) 
      return user;      
    } 

    return null; 
} 
3

Joe Kaplan and Ethan Wilansky अनुच्छेद उपयोग इस का उपयोग करते हुए इस समझे (System.DirectoryServices.AccountManagement dll को संदर्भित से):

using System.DirectoryServices.AccountManagement; 

private bool CheckUserinAD(string domain, string username) 
{ 
    PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domain); 
    UserPrincipal user = new UserPrincipal(domainContext); 
    user.Name = username; 
    PrincipalSearcher pS = new PrincipalSearcher(); 
    pS.QueryFilter = user; 
    PrincipalSearchResult<Principal> results = pS.FindAll(); 
    if (results != null && results.Count() > 0) 
     return true; 
    return false; 
} 
+0

डाउनवोट। ओपी ने कहा कि उसके पास व्यक्ति का वास्तविक नाम था, उपयोगकर्ता नाम नहीं, जैसे 'user.Name' ऊपर लेते हुए दिखाया गया है। यह उपयोगकर्ता नामों पर एक खोज करता है, पहला नाम नहीं, अंतिम नाम। – vapcguy

0

अन्य उत्तर खराब वर्णित किया गया है, कैसे का वर्णन नहीं किया उन्हें लागू करने के लिए, और अधिकांश ने गलत फिल्टर गुण दिए। तुम भी .Filter उपयोग करने की आवश्यकता नहीं है - तुम सिर्फ एक PrincipalSearcher जो कुछ भी स्थिति में है कि खोज से चलाता है का उपयोग करते हुए उस वस्तु पर खोज करते हैं, एक UserPrincipal वस्तु को अपने गुण (अंतिम नाम = .Surname, प्रथम नाम = .GivenName) या लेन-तब:

string firstName = txtFirstName.Text; 
string lastName = txtLastName.Text; 

PrincipalContext ctx = new PrincipalContext(ContextType.Domain); 

UserPrincipal up = new UserPrincipal(ctx); 
if (!String.IsNullOrEmpty(firstName)) 
    up.GivenName = firstName; 
if (!String.IsNullOrEmpty(lastName)) 
    up.Surname = lastName; 

PrincipalSearcher srch = new PrincipalSearcher(up); 
srch.QueryFilter = up; 

मैं यह सोचते कर रहा हूँ आप के साथ txtFirstName और txtLastName की आईडी/नाम इसे पाने के लिए प्रथम और अंतिम नाम के लिए बक्सें है,। ध्यान दें कि यदि आपके पास उस संपत्ति में कोई मूल्य नहीं है जिसे आप ढूंढ रहे हैं, तो इसे UserPrincipal पर न जोड़ें, या यह अपवाद का कारण बन जाएगा। ऊपर दिए गए चेक के लिए यही कारण है।

फिर आप srch पर एक .FindAll कर Principal वस्तुओं की एक PrincipalSearchResult संग्रह में खोज परिणामों को प्राप्त करने के लिए:

using (PrincipalSearchResult<Principal> results = srch.FindAll()) 
{ 
    if (results != null) 
    { 
     int resultCount = results.Count(); 
     if (resultCount > 0) // we have results 
     { 
      foreach (Principal found in results) 
      { 
       string username = found.SamAccountName; // Note, this is not the full user ID! It does not include the domain. 
      } 
     } 
    } 
} 

ध्यान दें कि परिणाम अशक्त नहीं होगा, भले ही इसके .Count()0 है, और क्यों दोनों चेकों हैं क्या आप वहां मौजूद हैं।

आपको लगता है कि foreach गुण आप की जरूरत प्राप्त करने के लिए का उपयोग कर पुनरावृति, और यह कैसे सी # का उपयोग कर ई में एक उपयोगकर्ता को खोजने के लिए की सवाल का जवाब है, लेकिन ध्यान दें कि आप केवल Principal वस्तु का उपयोग कर कुछ संपत्तियों के लिए प्राप्त कर सकते हैं, और अगर मैं Google के माध्यम से इस प्रश्न पर पहुंचे (जैसा मैंने किया), मैं बहुत निराश होगा। यदि आपको लगता है कि आपको बस इतना ही चाहिए - बढ़िया, आप कर चुके हैं! लेकिन बाकी को पाने के लिए (और अपनी खुद की विवेक को आराम दें), आपको नीचे उतरना होगा, और मैं वर्णन करूंगा कि यह कैसे करें।

मैंने पाया कि आप ऊपर दिए गए username का उपयोग नहीं कर सकते हैं, लेकिन आपको पूरे DOMAIN\doej नाम का नाम प्राप्त करना होगा। इस तरह आप ऐसा करते हैं। इस समारोह

private static string GetUserIdFromPrincipal(Principal prin) 
{ 
    string upn = prin.UserPrincipalName; 
    string domain = upn.Split('@')[1]; 
    domain = domain.Substring(0, domain.IndexOf(".YOURDOMAIN")); 

    // "domain" will be the subdomain the user belongs to. 
    // This may require edits depending on the organization. 

    return domain + @"\" + prin.SamAccountName; 
} 

एक बार जब आप गए हैं, आपको कॉल कर सकते हैं: इसके बजाय, कि foreach पाश में इस डाल से ऊपर,: और

string userId = GetUserIdFromPrincipal(found); 

इस फ़ंक्शन का उपयोग

public static string[] GetUserProperties(string strUserName) 
    { 
     UserPrincipal up = GetUser(strUserName); 
     if (up != null) 
     { 
      string firstName = up.GivenName; 
      string lastName = up.Surname; 
      string middleInit = String.IsNullOrEmpty(up.MiddleName) ? "" : up.MiddleName.Substring(0, 1); 
      string email = up.EmailAddress; 
      string location = String.Empty; 
      string phone = String.Empty; 
      string office = String.Empty; 
      string dept = String.Empty; 

      DirectoryEntry de = (DirectoryEntry)up.GetUnderlyingObject(); 
      DirectorySearcher ds = new DirectorySearcher(de); 
      ds.PropertiesToLoad.Add("l"); // city field, a.k.a location 
      ds.PropertiesToLoad.Add("telephonenumber"); 
      ds.PropertiesToLoad.Add("department"); 
      ds.PropertiesToLoad.Add("physicalDeliveryOfficeName"); 

      SearchResultCollection results = ds.FindAll(); 
      if (results != null && results.Count > 0) 
      { 
       ResultPropertyCollection rpc = results[0].Properties; 
       foreach (string rp in rpc.PropertyNames) 
       { 
        if (rp == "l") // this matches the "City" field in AD properties 
         location = rpc["l"][0].ToString(); 
        if (rp == "telephonenumber") 
         phone = FormatPhoneNumber(rpc["telephonenumber"][0].ToString());      
        if (rp == "physicalDeliveryOfficeName") 
         office = rpc["physicalDeliveryOfficeName"][0].ToString(); 
        if (rp == "department") 
         dept = rpc["department"][0].ToString(); 
       } 
      } 

      string[] userProps = new string[10]; 
      userProps[0] = strUserName; 
      userProps[1] = firstName; 
      userProps[2] = lastName; 
      userProps[3] = up.MiddleName; 
      userProps[4] = middleInit; 
      userProps[5] = email; 
      userProps[6] = location; 
      userProps[7] = phone; 
      userProps[8] = office; 
      userProps[9] = dept; 

      return userProps; 
     } 
     else 
      return null; 
    } 

    /// <summary> 
    /// Returns a UserPrincipal (AD) user object based on string userID being supplied 
    /// </summary> 
    /// <param name="strUserName">String form of User ID: domain\username</param> 
    /// <returns>UserPrincipal object</returns> 
    public static UserPrincipal GetUser(string strUserName) 
    { 
     PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain); 
     try 
     { 
      UserPrincipal oUserPrincipal = UserPrincipal.FindByIdentity(oPrincipalContext, strUserName); 
      return oUserPrincipal; 
     } 
     catch (Exception ex) { return null; } 
    } 

    public static string FormatPhoneNumber(string strPhoneNumber) 
    { 
     if (strPhoneNumber.Length > 0) 
      // return String.Format("{0:###-###-####}", strPhoneNumber); // formating does not work because strPhoneNumber is a string and not a number 
      return Regex.Replace(strPhoneNumber, @"(\d{3})(\d{3})(\d{4})", "$1-$2-$3"); 
     else 
      return strPhoneNumber; 
    } 

ध्यान दें कि FormatPhoneNumber फ़ंक्शन उत्तरी अमेरिकी संख्याओं के लिए है। यह एक संख्या लेगा (##########) और इसे ###-###-#### में अलग करें।,

string[] userProps = GetUserProperties(userId); 
string office = userProps[8]; 

लेकिन एक पूरे के समाधान के रूप में, आप भी इन परिणामों एक DataRow स्तंभ में जोड़ सकते हैं, और के रूप में यह वापसी:

फिर आप गुण इस तरह कि foreach पाश में प्राप्त कर सकते हैं, वापस DataTable का हिस्सा जिसे आप ListView या GridView से जोड़ सकते हैं।

/// <summary> 
    /// Gets matches based on First and Last Names. 
    /// This function takes a list of acceptable properties: 
    /// USERNAME 
    /// MIDDLE_NAME 
    /// MIDDLE_INITIAL 
    /// EMAIL 
    /// LOCATION 
    /// POST 
    /// PHONE 
    /// OFFICE 
    /// DEPARTMENT 
    /// 
    /// The DataTable returned will have columns with these names, and firstName and lastName will be added to a column called "NAME" 
    /// as the first column, automatically. 
    /// </summary> 
    /// <param name="firstName"></param> 
    /// <param name="lastName"></param> 
    /// <param name="props"></param> 
    /// <returns>DataTable of columns from "props" based on first and last name results</returns> 
    public static DataTable GetUsersFromName(string firstName, string lastName, List<string> props) 
    { 
     string userId = String.Empty; 
     int resultCount = 0; 

     DataTable dt = new DataTable(); 
     DataRow dr; 
     DataColumn dc; 

     // Always set the first column to the Name we pass in 
     dc = new DataColumn(); 
     dc.DataType = System.Type.GetType("System.String"); 
     dc.ColumnName = "NAME"; 
     dt.Columns.Add(dc); 

     // Establish our property list as columns in our DataTable 
     if (props != null && props.Count > 0) 
     { 
      foreach (string s in props) 
      { 
       dc = new DataColumn(); 
       dc.DataType = System.Type.GetType("System.String"); 
       if (!String.IsNullOrEmpty(s)) 
       { 
        dc.ColumnName = s; 
        dt.Columns.Add(dc); 
       } 
      } 
     } 

     // Start our search 
     PrincipalContext ctx = new PrincipalContext(ContextType.Domain); 

     UserPrincipal up = new UserPrincipal(ctx); 
     if (!String.IsNullOrEmpty(firstName)) 
      up.GivenName = firstName; 
     if (!String.IsNullOrEmpty(lastName)) 
      up.Surname = lastName; 

     PrincipalSearcher srch = new PrincipalSearcher(up); 
     srch.QueryFilter = up; 

     using (PrincipalSearchResult<Principal> results = srch.FindAll()) 
     { 
      if (results != null) 
      { 
       resultCount = results.Count(); 
       if (resultCount > 0) // we have results 
       { 
        foreach (Principal found in results) 
        { 
         // Iterate results, set into DataRow, add to DataTable 
         dr = dt.NewRow(); 
         dr["NAME"] = found.DisplayName; 

         if (props != null && props.Count > 0) 
         { 
          userId = GetUserIdFromPrincipal(found); 

          // Get other properties 
          string[] userProps = GetUserProperties(userId); 

          foreach (string s in props) 
          { 
           if (s == "USERNAME")     
            dr["USERNAME"] = userId; 

           if (s == "MIDDLE_NAME") 
            dr["MIDDLE_NAME"] = userProps[3]; 

           if (s == "MIDDLE_INITIAL") 
            dr["MIDDLE_INITIAL"] = userProps[4]; 

           if (s == "EMAIL") 
            dr["EMAIL"] = userProps[5]; 

           if (s == "LOCATION") 
            dr["LOCATION"] = userProps[6]; 

           if (s == "PHONE") 
            dr["PHONE"] = userProps[7]; 

           if (s == "OFFICE") 
            dr["OFFICE"] = userProps[8];          

           if (s == "DEPARTMENT") 
            dr["DEPARTMENT"] = userProps[9]; 
          } 
         } 
         dt.Rows.Add(dr); 
        } 
       } 
      } 
     } 

     return dt; 
    } 

आप इस तरह इस समारोह कहेंगे:

string firstName = txtFirstName.Text; 
string lastName = txtLastName.Text; 

List<string> props = new List<string>(); 
props.Add("OFFICE"); 
props.Add("DEPARTMENT"); 
props.Add("LOCATION"); 
props.Add("USERNAME"); 

DataTable dt = GetUsersFromName(firstName, lastName, props); 

DataTable, उन स्तंभों से भर दिया जाएगा और इस तरह मैंने किया, एक List<string> गुण मैं जरूरत से भर में भेज रहा है पहले कॉलम के रूप में NAME कॉलम, जिसमें उपयोगकर्ता के वास्तविक .DisplayName एडी से होंगे।

नोट: आप System.DirectoryServices और System.DirectoryServices.AccountManagement, System.Text.RegularExpressions, System.Data यह सब का उपयोग करने के संदर्भ होना चाहिए।

एचटीएच!

0

कोड मैं इस पोस्ट में देख रहे थे था:

 string uid = Properties.Settings.Default.uid; 
     string pwd = Properties.Settings.Default.pwd; 
     using (var context = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", uid, pwd)) 
     { 
      using (UserPrincipal user = new UserPrincipal(context)) 
      { 
       user.GivenName = "*adolf*"; 
       using (var searcher = new PrincipalSearcher(user)) 
       { 
        foreach (var result in searcher.FindAll()) 
        { 
         DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry; 
         Console.WriteLine("First Name: " + de.Properties["givenName"].Value); 
         Console.WriteLine("Last Name : " + de.Properties["sn"].Value); 
         Console.WriteLine("SAM account name : " + de.Properties["samAccountName"].Value); 
         Console.WriteLine("User principal name: " + de.Properties["userPrincipalName"].Value); 
         Console.WriteLine("Mail: " + de.Properties["mail"].Value); 

         PrincipalSearchResult<Principal> groups = result.GetGroups(); 

         foreach (Principal item in groups) 
         { 
          Console.WriteLine("Groups: {0}: {1}", item.DisplayName, item.Name); 
         } 
         Console.WriteLine(); 
        } 
       } 
      } 
     } 
     Console.WriteLine("End"); 
     Console.ReadLine(); 

ऐसा लगता है किसी भी चरित्र के लिए कि वाइल्डकार्ड तारा (*) है।

user.GivenName = "*firstname*"; 

अधिक में Microsoft documentation

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

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