DirectoryAccess クラスに追加した GetMembers メソッドのコードです。(これまでのコードはこちら VB C#)
VB
'指定したドメイングループのメンバーを取得します。
Public Shared Function GetMembers(group As DomainGroup) As IList(Of DomainObject)
If group Is Nothing Then
Throw New ArgumentNullException("group", "group が Nothing です。")
End If
If CanConnectDomain = False Then 'ドメインに接続できない時
Return New List(Of DomainObject)()
End If
Dim objects As New List(Of DomainObject)()
Using root = GetRootEntry() 'ルートのDirectoryEntryを取得
'このグループのメンバーを検索
Dim filter = String.Format("(memberOf={0})", group.Entry.Properties.Item("distinguishedName").Value)
Using searcher As New DirectorySearcher(root, filter)
Using results = searcher.FindAll()
For Each res As SearchResult In results
objects.Add(DirectCast(CreateInstance(res.GetDirectoryEntry()), DomainObject))
Next
End Using
'このグループをプライマリ グループとしているメンバーを検索
searcher.Filter = String.Format("(&(|(objectCategory={0})(objectCategory={1}))(primaryGroupID={2}))",
CategoryType.User, CategoryType.Computer, group.Token)
Using results = searcher.FindAll()
For Each res As SearchResult In results
objects.Add(DirectCast(CreateInstance(res.GetDirectoryEntry()), DomainObject))
Next
End Using
End Using
End Using
Return objects.OrderBy(Function(o) o.ToString()).ToList()
End Function
C#
//指定したドメイングループのメンバーを取得します。
public static IList<DomainObject> GetMembers(DomainGroup group)
{
if (group == null)
{
throw new ArgumentNullException("group", "group が null です。");
}
if (CanConnectDomain == false) //ドメインに接続できない時
{
return new List<DomainObject>();
}
var objects = new List<DomainObject>();
using (var root = GetRootEntry()) //ルートのDirectoryEntryを取得
{
//このグループのメンバーを検索
var filter = String.Format("(memberOf={0})", group.Entry.Properties["distinguishedName"].Value);
using (var searcher = new DirectorySearcher(root, filter))
{
using (var results = searcher.FindAll())
{
foreach (SearchResult res in results)
{
objects.Add((DomainObject)CreateInstance(res.GetDirectoryEntry()));
}
}
//このグループをプライマリ グループとしているメンバーを検索
searcher.Filter = String.Format("(&(|(objectCategory={0})(objectCategory={1}))(primaryGroupID={2}))",
CategoryType.User, CategoryType.Computer, group.Token);
using (var results = searcher.FindAll())
{
foreach (SearchResult res in results)
{
objects.Add((DomainObject)CreateInstance(res.GetDirectoryEntry()));
}
}
}
}
return objects.OrderBy(o => o.ToString()).ToList();
}
1 回目の検索はグループのメンバーの検索で、所属するグループがこのグループであるオブジェクトを検索してます。
プライマリ グループを除いて 所属するグループは memberOf 属性で取得できるので、この値がグループの distinguishedName 属性(識別名)の値に一致するものがあれば、メンバーはこのグループに所属していることになります。
例えば Enterprise Admins グループの distinguishedName 属性の値は次のようになってます。
CN=Enterprise Admins,CN=Users,DC=proceed,DC=pbyk,DC=com
また Administrator の 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 属性も distinguishedName 属性も値の書式が同じなので、これを検索条件として使ってます。
2 回目の検索はこのグループをプライマリ グループとしているユーザーかコンピューターを検索してます。
既定では、プライマリ グループは次のようになります。
ユーザー:Domain Users
ドメイン コントローラー:Domain Controllers
ドメイン コントローラー以外のコンピューター:Domain Computers
ユーザーかコンピューターの primaryGroupID 属性の値が グループの primaryGroupToken 属性の値(Token プロパティに保持)と一致すれば このグループに所属していることになります。
抽出されたメンバーは表示する名前でソートしてます。
内部で呼び出している CreateInstance メソッドを変更しました。太字部分の 1 行だけです。
VB
Private Shared Function CreateInstance(entry As DirectoryEntry) As DirectoryObject
Dim category As CategoryType
If [Enum].TryParse(Of CategoryType)(entry.SchemaClassName, True, category) = False Then
Throw New ArgumentException("entry の種類が CategoryType に該当しません。", "entry")
End If
Select Case category
Case CategoryType.User
If CanConnectDomain Then 'ドメインに接続できる時
Return New DomainUser(entry)
Else 'ドメインに接続できない時
Return New LocalUser(entry)
End If
Case CategoryType.Group
If CanConnectDomain Then 'ドメインに接続できる時
Return New DomainGroup(entry)
Else 'ドメインに接続できない時
Return New LocalGroup(entry)
End If
Case CategoryType.Computer
Return New Computer(entry)
Case CategoryType.PrintQueue
Return New PrintQueue(entry)
Case CategoryType.Volume
Return New Volume(entry)
Case Else
Return New ForeignSecurityPrincipal(entry)
End Select
End Function
C#
private static DirectoryObject CreateInstance(DirectoryEntry entry)
{
CategoryType category;
if (Enum.TryParse<CategoryType>(entry.SchemaClassName, true, out category) == false)
{
throw new ArgumentException("entry の種類が CategoryType に該当しません。", "entry");
}
switch (category)
{
case CategoryType.User:
if (CanConnectDomain) //ドメインに接続できる時
{
return new DomainUser(entry);
}
else //ドメインに接続できない時
{
return new LocalUser(entry);
}
case CategoryType.Group:
if (CanConnectDomain) //ドメインに接続できる時
{
return new DomainGroup(entry);
}
else //ドメインに接続できない時
{
return new LocalGroup(entry);
}
case CategoryType.Computer:
return new Computer(entry);
case CategoryType.PrintQueue:
return new PrintQueue(entry);
case CategoryType.Volume:
return new Volume(entry);
default:
return new ForeignSecurityPrincipal(entry);
}
}
Active Directory 関連 Blog
http://www.pbyk.com/blog/bloglist.html