2009-05-05 10 views
18

私はActive Directoryユーザーとコンピュータツールで "Find Users、Contacts、and Groups"の動作と同様にC#からADを検索する方法を理解しようとしています。私はグループ名、またはユーザーの名前を含む文字列を持っています(通常はfirstname middleinitialの形式ですが、必ずしもそうではありません)。ユーザーとグループのクエリを個別に実行しても、ほとんどのユーザーアカウントを取得する方法を見つけることはできません。ユーザー、連絡先、およびグループの検索ツールは、ほぼ毎回それらを戻します。誰でも何か提案がありますか?どのようにC#からActive Directoryのユーザーを見つけることができますか?

私は既にDirectorySearcherクラスの使い方を知っていますが、問題は私が望むものを見つけることができないということです。 cnとsamaccountのどちらの名前も、この中でユーザーの名前と関係がないので、それらを検索することはできません。分割してsnとgivenNameで検索しても、そのツールと同じくらい近くにキャッチしません。

+0

回答で続きを読むには、すべてのsAMAccountNameを使用する方法についてであり、彼らは非常に多くのupvotesを持っている理由私にはわからない:理由です。この質問は、プロパティを取得するためのファーストネームとファーストネームの使用に関するものです。トップ/マークされた正解だけが近くにあります。 – vapcguy

答えて

18

に適用するクエリでは、あなたは、.NET 3上にあります.5?もしそうなら - ADには.NET 3.5の大きな新機能があります - この記事ではEthan WilanskiとJoe KaplanのManaging Directory Security Principals in .NET 3.5をチェックしています。

大きな新機能の1つは、ADのユーザーおよび/またはグループの検索を大幅に簡素化する "PrincipalSearcher"クラスです。

.NET 3.5を使用できない場合は、「あいまいな名前解決」と呼ばれることがあります。これは少し知られている特殊な検索フィルタであり、すべての名前関連の属性をまとめて検索します。

は、このようなあなたのLDAP検索クエリを指定します。それはADのデフォルトで単一値およびインデックス付きなので

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

また、私はたくさんより速くなる、「objectCategoryの」属性でフィルタリングをお勧めします「objectClass」を使用します。

マルク・

+0

これはまさに私が探していたものです!どうもありがとう! – Sunookitsune

10

System.DirectoryServicesには2つの名前空間があります。DirectoryEntryとDirectorySearcher。ここでたDirectorySearcher上

さらに詳しい情報:アカウント名でフィルタしたい場合は、そのように...グループ、ユーザーなどでフィルタする

をFilterプロパティを使用することができます

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

.Filterを:

"(&(sAMAccountName=bsmith))" 

に設定し、FilterAllメソッドを実行します。これにより、ループバックしてユーザーに関する情報を取得できるSearchResultCollectionが返されます。

+0

ありがとう、私はDirectorySearcherについて知っています。問題は、私は広告でユーザーを見つけるためのクエリを思いつくことができないということです。 – Sunookitsune

+0

@Sunookitsune - あなたは正確な機能 "ユーザー、連絡先、およびグループの検索"を複製しようとしていますか? –

+0

@ Miyagi Coder私はその機能を正確には言いませんが、少なくともユーザーの検索方法の近くには何かがあります。あるいは、私が困惑しているので、うまくいくものを見つけてください。 – 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(); 
    } 
} 

userTypeは、ユーザー名のフォーマット方法に応じてsAMAccountNameまたはCNのいずれかにする必要があります。

例:
firstname.lastname(またはflastname)は通常のsAMAccountName
姓は通常、宮城の答えに追加するにはCN

+0

いいえ、 'sAMAccountName'はユーザー名です。つまり、DoeのDoejです.OPにはユーザー名がありません。あなたが 'userType'に' CN'を使い、 'username'の代わりに' FirstName LastName'を入れると言っているのであれば、実際にはフィルター ''(&(objectCategory = user)(objectClass = user)( givenName = "+ firstName +")(sn = "+ lastName +")) ";" – vapcguy

2

になりますでしょう....

はここ/フィルタですたDirectorySearcher

DirectorySearcher ds = new DirectorySearcher(); 

ds.Filter = "samaccountname=" + userName; 

SearchResult result = ds.FindOne(); 
+0

Bonzai Curtis !!!! –

+0

OPには、ユーザー名、つまりJohn Doeの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

Downvote。 OPは、ユーザー名ではなく、実際の名前を持っていると言っています。上記のように、「user.Name」のように表示されます。これは、名字、名字ではなくユーザー名の検索を行います。 – vapcguy

0

の方法については説明しませんでしたそれらを実装するために、そしてほとんどが間違ったフィルタプロパティを与えました。 .Filterを使用する必要はありません。UserPrincipalオブジェクトにプロパティ(姓:.Surname、名:= .GivenName)を割り当ててから、検索をトリガーするイベントが発生した場合でもPrincipalSearcherを使用してそのオブジェクトを検索します。

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; 

私はtxtFirstNametxtLastNameのIDS /名称で、あなたはそれを得るために最初と最後の名前のためのテキストボックスを持っていると仮定しています。探しているプロパティに値がない場合は、UserPrincipalに値を加えないでください。そうしないと例外が発生します。それが上記のチェックの理由です。結果はその.Count()0で、なぜ両方のチェックがされている場合でも、nullにならないことを

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. 
      } 
     } 
    } 
} 

注:

その後、PrincipalオブジェクトのPrincipalSearchResultコレクションに検索結果を取得するためにsrch.FindAllを行いますそこ。

あなたが必要なプロパティを取得するためにforeachことを利用して反復し、これはC#を使用してADでユーザーを見つける方法の質問に答える、しかし、あなただけPrincipalオブジェクトを使用していくつかのプロパティを取得することができます注意してください、と私の場合Googleを介してこの質問に達した(私がしたように)、私は非常に心配するだろう。あなたが必要とするものがすべて見つかった場合 - 偉大な、あなたは完了です!しかし、残りを得るために(そして自分の良心を休むために)、あなたは潜水しなければなりません。それをどうやって行うのかを説明します。

私はあなたがそれを使うことはできないことを発見しました。上記に入れましたが、DOMAIN\doej種類の名前を取得する必要があります。これがあなたのやり方です。

string userId = GetUserIdFromPrincipal(found); 

と、この機能を使用します:あなたは、この関数を呼び出すことができる、というたら

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ループでこれを入れ

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

:これは私が必要なプロパティで満たさList<string>に送信、それをやった方法です

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は、それらの列が入りますと、最初の列としてNAME列があり、ADのユーザーの実際の.DisplayNameになります。

注:あなたはこのすべてを使用するためにSystem.DirectoryServicesSystem.DirectoryServices.AccountManagementSystem.Text.RegularExpressionsSystem.Dataを参照する必要があります。

HTH!

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

関連する問題