組織単位(OU)用クラス(VB, C#, 説明)から呼び出される DirectoryAccess クラスの既存のメソッドのコードです。
まずは変更したメソッドです。(前回変更したコードはこちら)
指定した LDAP パスの所属パスを取得する GetBelongPath メソッドに OU を考慮するコード(太字の部分)を追加しました。
VB
Public Shared Function GetBelongPath(ldapPath As String) As String
If ldapPath Is Nothing Then
Return String.Empty
End If
If (ldapPath.Contains("OU=") OrElse ldapPath.Contains(",CN=")) = False Then 'ドメイン直下の時
'OUにある場合は・・・LDAP://ドメイン名/CN=○○,OU=OU名,~
'コンテナにある場合は・・・LDAP://ドメイン名/CN=○○,CN=コンテナ名,~
Return String.Empty
End If
Dim spos = ldapPath.LastIndexOf("CN=") '開始位置
If spos < 0 Then 'OUの時
spos = ldapPath.IndexOf("OU=")
End If
Dim epos = ldapPath.IndexOf(",DC=") '終了位置
Dim paths = ldapPath.Substring(spos, epos - spos).Split(","c) '"CN=○○"と"OU=○○"部分の配列
Array.Reverse(paths)
If ldapPath.Contains("OU=") Then 'OUがある時
If paths.Length = 1 Then 'ルートOU(自身)の時・・・LDAP://ドメイン名/OU=○○,DC=~
Return String.Empty
Else 'ルートOU以外の時
ReDim Preserve paths(paths.Length - 2) '自分の名前を除外
End If
End If
Dim sb As New StringBuilder()
For Each ou In paths
sb.AppendFormat("{0}/", ou.Substring(3))
Next
sb.Length -= 1
Return sb.ToString()
End Function
C#
public static string GetBelongPath(string ldapPath)
{
if (ldapPath == null)
{
return String.Empty;
}
if ((ldapPath.Contains("OU=") || ldapPath.Contains(",CN=")) == false) //ドメイン直下の時
{
//OUにある場合は・・・LDAP://ドメイン名/CN=○○,OU=OU名,~
//コンテナにある場合は・・・LDAP://ドメイン名/CN=○○,CN=コンテナ名,~
return String.Empty;
}
var spos = ldapPath.LastIndexOf("CN="); //開始位置
if (spos < 0) //OUの時
{
spos = ldapPath.IndexOf("OU=");
}
var epos = ldapPath.IndexOf(",DC="); //終了位置
var paths = ldapPath.Substring(spos, epos - spos).Split(','); //"CN=○○"と"OU=○○"部分の配列
Array.Reverse(paths);
if (ldapPath.Contains("OU=")) //OUがある時
{
if (paths.Length == 1) //ルートOU(自身)の時・・・LDAP://ドメイン名/OU=○○,DC=~
{
return String.Empty;
}
else //ルートOU以外の時
{
Array.Resize<string>(ref paths, paths.Length - 1); //自分の名前を除外
}
}
var sb = new StringBuilder();
foreach (var ou in paths)
{
sb.AppendFormat("{0}/", ou.Substring(3));
}
sb.Length--;
return sb.ToString();
}
指定した名前と種類の Directory オブジェクトを検索する FindDirectoryObject メソッドに OU 部分のコード(太字の部分)を追加し、アクセス修飾子を変更しました。
VB
Friend Shared Function FindDirectoryObject(name As String, objectCategory As CategoryType) As DirectoryObject
If name Is Nothing Then
Throw New ArgumentNullException("name", "name が Nothing です。")
End If
If IsValidCategoryType(objectCategory) = False Then
Throw New InvalidEnumArgumentException("objectCategory が有効な CategoryType ではありません。")
End If
Using root = GetRootEntry() 'ルートのDirectoryEntryを取得
If CanConnectDomain Then 'ドメインに接続できる時
Dim filter As String
Select Case objectCategory
Case CategoryType.User
filter = String.Format("(&(objectCategory={0})(sAMAccountName={1}))", objectCategory, name)
Case CategoryType.OrganizationalUnit
filter = String.Format("(&(objectCategory={0})(distinguishedName={1}))", objectCategory, name)
Case CategoryType.PrintQueue
filter = String.Format("(&(objectCategory={0})(printerName={1}))", objectCategory, name)
Case Else
filter = String.Format("(&(objectCategory={0})(name={1}))", objectCategory, name)
End Select
Using searcher As New DirectorySearcher(root, filter)
Dim result = searcher.FindOne()
Return If(result Is Nothing, Nothing, CreateInstance(result.GetDirectoryEntry()))
End Using
Else 'ドメインに接続できない時 <-- こっちはローカル
Return CreateInstance(root.Children.Find(name, objectCategory.ToString()))
End If
End Using
End Function
C#
internal static DirectoryObject FindDirectoryObject(string name, CategoryType objectCategory)
{
if (name == null)
{
throw new ArgumentNullException("name", "name が null です。");
}
if (IsValidCategoryType(objectCategory) == false)
{
throw new InvalidEnumArgumentException("objectCategory が有効な CategoryType ではありません。");
}
using (var root = GetRootEntry()) //ルートのDirectoryEntryを取得
{
if (CanConnectDomain) //ドメインに接続できる時
{
string filter;
switch (objectCategory)
{
case CategoryType.User:
filter = String.Format("(&(objectCategory={0})(sAMAccountName={1}))", objectCategory, name);
break;
case CategoryType.OrganizationalUnit:
filter = String.Format("(&(objectCategory={0})(distinguishedName={1}))", objectCategory, name);
break;
case CategoryType.PrintQueue:
filter = String.Format("(&(objectCategory={0})(printerName={1}))", objectCategory, name);
break;
default:
filter = String.Format("(&(objectCategory={0})(name={1}))", objectCategory, name);
break;
}
using (var searcher = new DirectorySearcher(root, filter))
{
var result = searcher.FindOne();
return (result == null) ? null : CreateInstance(result.GetDirectoryEntry());
}
}
else //ドメインに接続できない時 <-- こっちはローカル
{
return CreateInstance(root.Children.Find(name, objectCategory.ToString()));
}
}
}
DirectoryObject のインスタンスを作成する CreateInstance メソッドに OU 部分のコード(太字の部分)を追加しました。
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.OrganizationalUnit
Return New OrganizationalUnit(entry)
Case CategoryType.PrintQueue
Return New PrintQueue(entry)
Case CategoryType.Volume
Return New Volume(entry)
Case Else
Throw New NotImplementedException()
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.OrganizationalUnit:
return new OrganizationalUnit(entry);
case CategoryType.PrintQueue:
return new PrintQueue(entry);
case CategoryType.Volume:
return new Volume(entry);
default:
throw new NotImplementedException();
}
}
次は変更してないメソッドです。
指定した Directory オブジェクトの使用されているリソースを解放します。
VB
Public Shared Sub DisposeItems(items As IEnumerable(Of IDirectory))
If items Is Nothing Then
Throw New ArgumentNullException("items", "items が Nothing です。")
End If
For Each item In items
item.Dispose()
Next
End Sub
C#
public static void DisposeItems(IEnumerable<IDirectory> items)
{
if (items == null)
{
throw new ArgumentNullException("items", "items が null です。");
}
foreach (var item in items)
{
item.Dispose();
}
}