前回管理者が管理ツール「Active Directory ユーザとコンピュータ」で主に管理するオブジェクトは主に次の 6つだと書きました。
・ユーザ
・グループ
・コンピュータ
・組織単位(OU)
・プリンタ
・共有フォルダ
これらのオブジェクトはどれも DirectoryEntry オブジェクトで表されます。プロパティは DirectoryEntry.Properties.Item("name").Value のように取得・設定したいプロパティ名を文字列で指定しないといけません。値は Object 型なので、取得時はキャストが必要な場合が多いと思います。
それに管理ツールで設定できる項目なのにプロパティ名が存在しない(DirectoryEntry.Properties.PropertyNames プロパティのコレクション内に名前がない)ものもあります。
こういう時は ADSI(Active Directory Service Interfaces)を使うという方法があります。
ADSI は COM なので参照を追加する場合は「COM」タブから「Active DS Type Library」を選びます。
各オブジェクトとそれに対応するインターフェイスです。
ユーザ | IADsUser |
グループ | IADsGroup |
コンピュータ | IADsComputer |
組織単位(OU) | IADsOU |
プリンタ | IADsPrintQueue |
共有フォルダ | |
共有フォルダだけ対応するインターフェイスが判りませんでした。
これらのインターフェイスは IADs インターフェイスを継承しています。
使い方は DirectoryEntry.NativeObject プロパティを上記インターフェイスにキャストするだけです。
個人的には DirectoryEntry と ADSI 併用し、プロパティは DirectoryEntry を優先して使ってます。
というのも、Windows アプリとして作る場合、設定・表示画面のコントロールにバインドするためのクラスをオブジェクトごとに作るんですが、そのクラス内に DirectoryEntry オブジェクトを保持してプロパティとして公開、必要であればインターフェイスにキャストしたオブジェクトも保持して必要ならプロパティとして公開してます。例をあげますと、
ユーザとコンピュータには「所属するグループ」があります。これは次のように調べます。(画面側)
For Each group In groups ‘全グループ
If group.Native.IsMember(user.Entry.Path) Then 'グループに所属している時
groupListBox.Items.Add(group.Name) ‘リストボックスにグループ名を追加
End If
Next
group.Native プロパティが IADsGroup インターフェイス、user.Entryプロパティが DirectoryEntry です。IADsGroup.IsMember(DirectoryEntry.Path) で、引数に指定したアカウント(のパス)がこのグループのメンバかどうか判別します。
実はこれだけでは所属するグループすべてを取得できないんです。取得のしかたは別途書きますね。
また、グループには「メンバ」と「所属するグループ」があります。これらはそれぞれ次のように処理します。
For Each member As IADs In group.Members() ‘メンバ(Members メソッドの戻り値の型は IADsMembers)
'リストビューにアイテムを追加
Next
Dim groupObjects As Object '所属するグループ
Try
groupObjects = group.GetEx("memberOf") ‘IADs.GetEx メソッド(取得したいプロパティを文字列で指定)
Catch '所属するグループがない
Return
End Try
For Each groupObject As String In DirectCast(groupObjects, IEnumerable)
'リストビューにアイテムを追加
Next
管理ツールではプリンタのプロパティに「モデル」の項目(全般タブ)があります。
そこでプリンタを表すクラス(PrintQueue クラス)に Model プロパティを公開します。
Public Property Model As String
Get
If MyBase.IsDisposed Then
Throw New ObjectDisposedException(Me.GetType().Name)
End If
Try
Return DirectCast(MyBase.Entry.NativeObject, IADsPrintQueue).Model
Catch
Return Nothing
End Try
End Get
Set(value As String)
If MyBase.IsDisposed Then
Throw New ObjectDisposedException(Me.GetType().Name)
End If
DirectCast(MyBase.Entry.NativeObject, IADsPrintQueue).Model = value
End Set
End Property
Get の部分でインターフェイスのプロパティを返すとこ、Try ブロックで囲ってます。
なぜかというと、値が設定されてないとプロパティにアクセスした時に例外が発生するからです。さっき DirectoryEntry を優先して使ってるって書いたのはこれが理由です。
「説明」のように未設定が可能な項目のプロパティ実装は 各インターフェイスの Description プロパティを返すよりも String 型にキャストした DirectoryEntry.Properties.Item("description").Value プロパティを返す方がいいのかなと(未設定だと Nothing を返すので)。
サンプルアプリのクラスライブラリ側は、次のインターフェイスとクラスがあります。
・IDirectory(Directory オブジェクトのプロパティを定義、IDisposable を継承)
・IDomain(ドメインの Directory オブジェクトのプロパティを定義、IDirectory を継承)
・IUser(User オブジェクトの共通プロパティを定義、IDirectory を継承)
・IGroup(Group オブジェクトの共通プロパティを定義、IDirectory を継承)
・DirectoryObject(Directory オブジェクトを表す抽象基本クラス、IDirectory を実装)
・DomainObject(ドメインの Directory オブジェクトを表す抽象基本クラス、DirectoryObject を継承し IDomain を実装)
・LocalUser(ローカルのユーザを表すクラス、DirectoryObject を継承し IUser を実装)
・DomainUser(ドメインのユーザを表すクラス、DomainObject を継承し IUser を実装)
・LocalGroup(ローカルのグループを表すクラス、DirectoryObject を継承し IGroup を実装)
・DomainGroup(ドメインのグループを表すクラス、DomainObject を継承し IGroup を実装)
・Computer(コンピュータを表すクラス、DomainObject を継承)
・OrganizationalUnit(組織単位(OU)を表すクラス、DomainObject を継承)
・PrintQueue(プリンタを表すクラス、DomainObject を継承)
・Volume(共有フォルダを表すクラス、DomainObject を継承)
これらのクラスは BindingSource へのバインド用です。あと、静的メソッド・プロパティを提供する DirectoryAccess クラスがあります。
おまけ
Excel でセルに表示されている値を非表示にする時は、セルの書式設定の「表示形式」タブで「ユーザー定義」を選んで、「種類」のところに セミコロン3つ(;;;)を指定。