.NETからActive Directoryデータにアクセス ~組織単位(OU)情報の取得と表示~

2,873 views
2,594 views

Published on

Get OrganizationalUnit(OU) objects from Active Directory and display on a windows/web form.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,873
On SlideShare
0
From Embeds
0
Number of Embeds
194
Actions
Shares
0
Downloads
9
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

.NETからActive Directoryデータにアクセス ~組織単位(OU)情報の取得と表示~

  1. 1. .NETからActive Directoryデータにアクセス 組織単位(OU)情報を表示する 小山 三智男 mitchin Microsoft MVP for Directory Services
  2. 2. サンプルアプリケーション 2 開発環境 • Domain:Windows Server 2008、Windows Server 2012 R2 • Client:Windows 8.1 Pro、Windows 7 Professional SP1 • IDE:Visual Studio Professional 2013 • Projects:Windows Forms(.NET 4.5.1) Web Forms(.NET 4.5.1) IE11、IE10 Class Library(.NET 4.5.1) ※ソースコード自体は .NET 4 相当 実行環境 • DC:Windows Server 2008 Standard SP2(.NET 4.5.1) • IIS:Windows 認証 • Client:Windows 7 Professional SP1、IE10
  3. 3. 3 参照設定 •.NETから Active Directory の色々な情報にアクセスするために System.DirectoryServices アセンブリを参照する必要がありま す。 •ドメインやサイト関連は System.DirectoryServices. ActiveDirectory 名前空間にそれらを表すクラスがあり、Active Directory の管理タスクを自動化するために使用されます。 •Active Directory 内のデータにアクセスするために使用される のは System.DirectoryServices 名前空間で、オブジェクトを カプセル化する DirectoryEntry クラスやクエリを実行する DirectorySearcher クラスなどがあります。 •ADSI(Active Directory Services Interfaces)を使用してネイ ティブなオブジェクトを扱う場合は Active DS Type Libraryを 参照する必要があります。
  4. 4. 4 主にどんなデータがあるの? 管理ツール「Active Directory ユーザとコンピュータ」で管理す る以下のオブジェクト • ユーザ • グループ • コンピュータ • 組織単位(OU) • プリンタ • 共有フォルダ
  5. 5. ADSI 基本インターフェイスは IADs で、各オブジェクトはこのイン ターフェイスを継承しています。 DirectoryEntry.NativeObject プロパティの値を上記インター フェイスにキャストできます。但し IADsComputer は LDAP をサポートしていないので 実質キャストできません。 5 ユーザ IADsUser グループ IADsGroup コンピュータ IADsComputer 組織単位(OU) IADsOU プリンタ IADsPrintQueue 共有フォルダ
  6. 6. 6 どうやって接続するの? ドメインに接続するには LDAP を使います。 プロバイダ:LDAP(Lightweight Directory Access Protocol) 書式例:LDAP://DC=virtual,DC=proceed,DC=local この LDAP の接続文字列を引数にして DirectoryEntry のインス タンスを作成します。 作成した DirectoryEntry がドメインを表し、検索のルートにな ります。(DirectorySearcher の引数になります。) この場合、検索範囲はドメイン全体ということになります。
  7. 7. 検索してOUのリストを取得する • 接続するドメインや取得したOUは DirectoryEntry オブジェクト • ユーザやOUを検索するのは DirectorySearcher オブジェクト • 複数の検索結果は SearchResultCollection として返される • SearchResult.GetDirectoryEntry メソッドで DirectoryEntry を取得 • LDAP書式のフィルター文字列(DirectorySearcher.Filter プロパティ)は 次のように指定(属性=値 をカッコで括る) • "(objectCategory=OrganizationalUnit)" -- OU • "(&(objectCategory=OrganizationalUnit)(!location=*本社))" -- 本社 以外のOU • "(&(objectCategory=OrganizationalUnit)(|(st=東京都)(st=大阪府)))" -- 都道府県が東京か大阪のOU 7
  8. 8. サンプルアプリケーションの初期画面 ドメインを取得して画面下部に 接続先を表示しています。 8
  9. 9. プロパティと属性の対応 プロパティ画面の「全般」タブの項目に対応する属性です。 9
  10. 10. 組織単位リスト画面(Windowsアプリ) 10
  11. 11. 組織単位リスト画面(Webアプリ) 11
  12. 12. クラスライブラリ側に追加したクラス OrganizationalUnit (組織単位を表すクラス) プロパティ • City (市区町村を取得または設定) • PostalCode (郵便番号を取得または設定) • Prefecture (都道府県を取得または設定) • StoredDomainObjects (直下のオブジェクトを取得) • Street (番地を取得または設定) メソッド • FindByPath (データバインド用:指定したパスのOUを検索) • Dispose (オーバーライド:リソースを解放) 12
  13. 13. フォーム側(Windowsアプリ) • BindingSource のデータソースに OrganizationalUnit クラス を指定 • 初期画面と同じ内容の ImageList を一覧 TreeView 及び直下 のデータ表示用 ListView のイメージに設定 • 詳細の「データ」以外の各コントロールは BindingSource(ク ラス)のプロパティにバインド • OU の一覧を取得し、表示用のパスと名前でソートしたものを 内部保持してそれを BindingSource のデータソースに設定 • 取得した OU の数を表示 • 一覧 TreeView に OU のノードを作成して追加 • 一覧から OU を選択すると、内部保持しているリストから 選択 された OU を抽出し、OUBindingSource の Position を設定 • 選択された OU に格納されているデータを ListView に表示 13
  14. 14. フォーム側(Webアプリ) • OrganizationalUnit クラスをビジネスオブジェクトとする ObjectDataSource を詳細 FormView のデータソースに指定、 SELECT 操作に FindByPath メソッドを指定し パラメータ ソースに一覧 TreeView の SelectedValue を指定 • OU の一覧を取得し、表示用のパスと名前でソートしたものを 内部保持してそれを BindingSource のデータソースに設定 • 取得した OU の数を表示 • OU に格納されているデータ格納用の Dictionary を初期化して ViewState に保持 • 一覧 TreeView に OU のノードを作成して追加 • 一覧から OU を選択すると、格納されているデータから DataTable を作成してデータ表示用 GridView にバインドし Dictionary に追加(ある場合は DataTable を取り出す) 14
  15. 15. 組織単位取得サンプルコード(VB) Public Shared Function GetOrganizationalUnits( ) As IList(Of OrganizationalUnit) Dim ous As New List(Of OrganizationalUnit)() Using root = GetRootEntry() 'ルートのDirectoryEntryを取得 Dim filter = "(objectCategory=OrganizationalUnit)" Using searcher As New DirectorySearcher(root, filter) Using results = searcher.FindAll() For Each res As SearchResult In results ous.Add(DirectCast(CreateInstance(res.GetDirectoryEntry()), OrganizationalUnit)) 'DirectoryObject を作成して追加 Next End Using End Using End Using Return ous End Function ※root は一般的には New DirectoryEntry(LDAPのルートパス) をセット 15
  16. 16. 組織単位取得サンプルコード(C#) public static IList<OrganizationalUnit> GetOrganizationalUnits() { var ous = new List<OrganizationalUnit>(); using (var root = GetRootEntry()) { //ルートのDirectoryEntryを取得 var filter = "(objectCategory=OrganizationalUnit)"; using (var searcher = new DirectorySearcher(root, filter)) { using (var results = searcher.FindAll()) { foreach (SearchResult res in results) { ous.Add((OrganizationalUnit)CreateInstance( res.GetDirectoryEntry())); //DirectoryObject を作成して追加 } } } } return ous; } ※root は一般的には new DirectoryEntry(LDAPのルートパス) をセット 16
  17. 17. 直下のデータ取得サンプルコード(VB) Friend Shared Function GetStoredDomainObjects( ou As OrganizationalUnit) As List(Of DomainObject) Dim objects As New List(Of DomainObject)() Using searcher As New DirectorySearcher(ou.Entry) searcher.SearchScope = SearchScope.OneLevel Using results = searcher.FindAll() For Each res As SearchResult In results objects.Add(DirectCast(CreateInstance(res.GetDirectoryEntry()), DomainObject)) 'DirectoryObject を作成して追加 Next End Using End Using Return objects.OrderBy(Function(o) o.Name).ToList() End Function ※直下のデータのみ必要なので DirectorySearcher.SearchScope プロパティ に SearchScope.OneLevel を指定(検索ルートは対象のOU) 17
  18. 18. 直下のデータ取得サンプルコード(C#) internal static List<DomainObject> GetStoredDomainObjects(OrganizationalUnit ou) { var objects = new List<DomainObject>(); using (var searcher = new DirectorySearcher(ou.Entry)) { searcher.SearchScope = SearchScope.OneLevel; using (var results = searcher.FindAll()) { foreach (SearchResult res in results) { objects.Add((DomainObject)CreateInstance( res.GetDirectoryEntry())); //DirectoryObject を作成して追加 } } } return objects.OrderBy(o => o.Name).ToList(); } ※直下のデータのみ必要なので DirectorySearcher.SearchScope プロパティ に SearchScope.OneLevel を指定(検索ルートは対象のOU) 18
  19. 19. 組織単位の検索サンプルコード(VB) <DataObjectMethod(DataObjectMethodType.Select)> Public Shared Function FindByPath(path As String) As OrganizationalUnit 'distinguishedNameを生成 Dim ouNames = path.Split("/"c).Reverse() Dim sb As New StringBuilder() For Each ouName In ouNames sb.AppendFormat("OU={0},", ouName) Next For Each dc In DirectoryAccess.DomainName.Split("."c) sb.AppendFormat("DC={0},", dc) Next sb.Length -= 1 Return DirectCast(DirectoryAccess.FindDirectoryObject(sb.ToString(), CategoryType.OrganizationalUnit), OrganizationalUnit) End Function 19
  20. 20. 組織単位の検索サンプルコード(C#) [DataObjectMethod(DataObjectMethodType.Select)] internal static OrganizationalUnit FindByPath(string path) { //distinguishedNameを生成 var ouNames = path.Split('/').Reverse(); var sb = new StringBuilder(); foreach (var ouName in ouNames) { sb.AppendFormat("OU={0},", ouName); } foreach (var dc in DirectoryAccess.DomainName.Split('.')) { sb.AppendFormat("DC={0},", dc); } sb.Length--; return (OrganizationalUnit)DirectoryAccess.FindDirectoryObject( sb.ToString(), CategoryType.OrganizationalUnit); } 20
  21. 21. 詳細や関連情報はブログ等で .NETからActive Directoryデータにアクセス ~共有フォルダの取得と表示~ http://www.slideshare.net/mitchin227/display-folder ユーザやグループの検索 http://blogs.wankuma.com/mitchin/archive/2013/06/26/327958.aspx Active Directory 内のオブジェクトの検索指定 http://blogs.wankuma.com/mitchin/archive/2013/06/28/327969.aspx 組織単位(OU) http://blogs.wankuma.com/mitchin/archive/2014/03/01/328414.aspx 組織単位(OU)用のクラス http://blogs.wankuma.com/mitchin/archive/2014/03/02/328419.aspx http://blogs.wankuma.com/mitchin/archive/2014/03/04/328422.aspx DirectoryAccessクラスに追加した組織単位(OU)関連のメソッド http://blogs.wankuma.com/mitchin/archive/2014/03/11/328434.aspx Windows Server 2012 R2でActive Directory始めました。 http://blogs.wankuma.com/mitchin/archive/2014/05/05/330117.aspx 21

×