前回ユーザとコンピュータについて「これだけでは所属するグループすべてを取得できない」と書きました。
何が取得できないかというと、プライマリ グループが取得できないんです。
プライマリ グループはユーザまたはコンピュータのプロパティの「所属するグループ」タブにあります。(クリックすると新しいウィンドウで拡大図が表示されます。)
ADネタのところで DirectoryAccess クラスの実装を書きましたが、そこに追加実装したものを抜粋ですが書いときます。列挙体は名前空間直(クラスの外)です。
列挙体
Public Enum CategoryType 'ディレクトリ オブジェクトの種類
User 'ユーザ
Group 'グループ
Computer 'コンピュータ
OrganizationalUnit '組織単位(OU)
PrintQueue 'プリンタ
Volume '共有フォルダ
End Enum
プライベートフィールド
Private Shared _groupTokens As Dictionary(Of Integer, String) 'ドメイングループのPrimaryGroupTokenと名前の組のリスト
パブリック プロパティ
'ドメイングループのPrimaryGroupTokenと名前の組のリストを取得
Public Shared ReadOnly Property GroupTokens As Dictionary(Of Integer, String)
Get
Return _groupTokens
End Get
End Property
パブリック メソッド
Public Shared Function GetGroups() As IList(Of IGroup) 'グループのリストを取得
Dim groups As New Collection(Of IGroup)()
Using root As New DirectoryEntry(LdapRootPath)
If IsLogonDomain Then 'ドメインにログオンしている時
Dim filter = String.Format("(objectCategory={0})", CategoryType.Group)
Using searcher As New DirectorySearcher(root, filter)
Using results = searcher.FindAll()
Dim entry As DirectoryEntry
Dim token As Integer
_groupTokens = New Dictionary(Of Integer, String)(results.Count)
For Each res As SearchResult In results
entry = res.GetDirectoryEntry()
groups.Add(DirectCast(CreateInstance(entry), IGroup))
entry.Invoke("GetInfoEx", New Object() {"primaryGroupToken"}, 0)
token = Convert.ToInt32(entry.Properties.Item("primaryGroupToken").Value)
If _groupTokens.ContainsKey(token) = False Then
_groupTokens.Add(token, PathToCn(entry.Name))
End If
Next
End Using
End Using
Else 'ドメインにログオンしていない時
‘省略 ?-> ユーザやグループなどの情報の検索と取得 を参考にしてください。
End If
End Using
Return groups
End Function
プライベート メソッド
Private Shared Function CreateInstance(entry As DirectoryEntry) As DirectoryObject '指定した DirectoryEntry の DirectoryObject インスタンスを作成
Select Case DirectCast([Enum].Parse(GetType(CategoryType), entry.SchemaClassName, True), CategoryType)
Case CategoryType.User
If IsLogonDomain Then 'ドメインにログオンしている時
Return New DomainUser(entry)
Else 'ドメインにログオンしていない時
Return New LocalUser(entry)
End If
Case CategoryType.Group
If IsLogonDomain Then 'ドメインにログオンしている時
Return New DomainGroup(entry)
Else 'ドメインにログオンしていない時
Return New LocalGroup(entry)
End If
Case CategoryType.Computer
Return New Computer(entry)
Case CategoryType.OrganizationalUnit
Return New OrganizationalUnit(entry)
Case CategoryType.PrintQueue
Return New PrintQueue(entry)
Case CategoryType.Volume
Return New Volume(entry)
Case Else
Throw New ArgumentException("entry の種類が CategoryType に該当しません。", "entry")
End Select
End Function
グループの DirectoryEntry は primaryGroupToken プロパティが PropertyCollection 内にないので、「primaryGroupToken プロパティを使うよ~」って言ってあげないといけないんです。
それをやってるところが GetGroups メソッド内のこの部分。
entry.Invoke("GetInfoEx", New Object() {"primaryGroupToken"}, 0)
これは ADSI の IADs.GetInfoEx("primaryGroupToken", 0) を呼び出したのと同じです。最後の引数(lnReserved パラメータ)に 0 を指定してますが、理由は判りません。お約束ということで。
これでグループの primaryGroupToken(整数値)が取得できたので、primaryGroupToken(キー)とグループ名(値)を Dictionary に追加します。
ユーザの DirectoryEntry は primaryGroupID プロパティを持っています。
つまり、グループの primaryGroupToken = ユーザの primaryGroupID なら、そのグループがユーザのプライマリ グループとなるわけです。(Dictionary から primaryGroupID をキーにしてグループ名を取得する)
おまけ
Excel で 数値が入力されてるセルの書式を ユーザ定義にして 種類を「[DBNum1]」や「[DBNum3]」にすると変わった形で表示されます。(バージョンや環境によって異なるかも)