所属しているすべてのグループを表示する画面の Windows アプリの VB のコードです。
'プライベートフィールド
Private ReadOnly member As DomainObject 'メンバー
Private ReadOnly allGroups As Dictionary(Of String, DomainGroup) '全グループ(Key:distinguishedName)
Private ReadOnly addedDisplayNames As List(Of String) 'リストに追加したグループの表示テキスト
'パブリックコンストラクター
Public Sub New(member As DomainObject)
InitializeComponent()
Me.member = member
allGroups = DirectoryAccess.GetGroups(Of DomainGroup)().ToDictionary(
Function(group) group.Entry.Properties.Item("distinguishedName").Value.ToString(), Function(group) group)
addedDisplayNames = New List(Of String)()
Me.AddChildNode() '子ノードを追加
Me.GroupListBox.DataSource = addedDisplayNames
Me.ViewPanel.Enabled = addedDisplayNames.Count > 1
Me.GroupTreeView.ExpandAll()
End Sub
'イベントハンドラ
Private Sub RadioButton_CheckedChanged(
sender As Object, e As EventArgs) Handles TreeRadioButton.CheckedChanged, ListRadioButton.CheckedChanged
Me.GroupTreeView.Visible = sender Is Me.TreeRadioButton
Me.GroupListBox.Visible = Not Me.GroupTreeView.Visible
End Sub
'プライベートメソッド
'子ノードを追加
Private Sub AddChildNode()
Dim node As New TreeNode(member.ToString(), member.Category, member.Category)
Me.GroupTreeView.Nodes.Add(node)
If (member.Category = CategoryType.User) OrElse (member.Category = CategoryType.Computer) Then
'プライマリー グループを追加
Dim primaryGroupId = If(member.Category = CategoryType.User,
DirectCast(member, DomainUser).PrimaryGroupId, DirectCast(member, Computer).PrimaryGroupId)
Dim group = allGroups.Values.Cast(Of DomainGroup)().Single(Function(grp) grp.Token = primaryGroupId)
Me.AddChildNode(node, group) '子ノードを追加
End If
'所属するグループを追加
For Each memberOf As String In member.Entry.Properties.Item("memberOf")
Me.AddChildNode(node, allGroups.Item(memberOf)) '子ノードを追加
Next
End Sub
'子ノードを追加
Private Sub AddChildNode(node As TreeNode, group As DomainGroup)
Dim childNode = CreateNode(group) 'ノードを作成
node.Nodes.Add(childNode)
If addedDisplayNames.Contains(childNode.Text) = False Then
addedDisplayNames.Add(childNode.Text) '表示するテキストを追加
End If
'ネストしているグループを追加
For Each memberOf As String In group.Entry.Properties.Item("memberOf")
Me.AddChildNode(childNode, allGroups.Item(memberOf)) '子ノードを追加
Next
End Sub
'指定したグループのノードを作成
Private Function CreateNode(group As DomainGroup) As TreeNode
Dim displayName = String.Format("{0}({1})", group.Name, group.Scope) '表示するテキスト
Dim fontColor As Color
Select Case group.ScopeType
Case DomainGroupScopeType.DomainLocal
fontColor = Color.Blue
Case DomainGroupScopeType.Global
fontColor = Color.Green
Case DomainGroupScopeType.Universal
fontColor = Color.Brown
End Select
Return New TreeNode(displayName) With {.Name = group.Name, .ForeColor = fontColor}
End Function
Dispose メソッドに次のコードを追加しました。
DirectoryAccess.DisposeItems(allGroups.Values)
コンストラクターで受け取っているメンバーは、呼出し元のリスト画面で選択されたオブジェクトで、ユーザー、グループまたはコンピューターです。
そのメンバーの所属するグループを再帰的に取得してます。
所属するグループはその都度検索して取得するのではなく、事前にすべてのグループを取得して、取り出しやすいよう distinguishedName 属性(識別名)の値をキーにした Dictionary から取得するようにしました。
ドメインの規模が大きい場合はその都度検索した方がいいかもしれないですね。
DirectoryAccess.GetGroups メソッドの実装は CodePlex の方をご覧ください。
所属するグループは memberOf 属性で取得できるので、For Each で回して取得してます。
例えば Administrator だと distinguishedName 属性と memberOf 属性の値は次のようになります。
distinguishedName 属性の値
CN=Administrator,CN=Users,DC=proceed,DC=pbyk,DC=com
memberOf 属性の値
CN=Group Policy Creator Owners,CN=Users,DC=proceed,DC=pbyk,DC=com
CN=Domain Admins,CN=Users,DC=proceed,DC=pbyk,DC=com
CN=Enterprise Admins,CN=Users,DC=proceed,DC=pbyk,DC=com
CN=Schema Admins,CN=Users,DC=proceed,DC=pbyk,DC=com
CN=Administrators,CN=Builtin,DC=proceed,DC=pbyk,DC=com
見ての通り書式が同じなので、memberOf 属性の値をキーにして Dictionary から所属するグループのオブジェクトを取り出してます。
あと、ユーザーとコンピューターはプライマリー グループがあり、これは memberOf 属性に含まれないので別途取得してます。
取得は簡単で、ユーザーやコンピューターの primaryGroupID 属性の値(PrimaryGroupId プロパティに保持)= グループの primaryGroupToken 属性の値(Token プロパティに保持)であるグループを Dictionary から検索してます。
Active Directory 関連 Blog
http://www.pbyk.com/blog/bloglist.html