2011/07/31

PowerShellでActive Directoryのグループのメンバを大量に取得

Active DirectoryをPowerShellで管理』で、PowerShell を使って、Active Directory のグループのメンバを取得する方法について書いた。
しかし、これには実は問題が二つある。一つ目は、グループのメンバ数が大量だったときにエラーが起こるという問題だ。二つ目は、所属関係の問い合わせを直接解決することができないという問題だ。どちらの問題も、PowerShell のActive Directory モジュールの問題で、代わりにADSIを利用することで解決できる。

まず一つ目の問題。例えば、次のようなエラーが発生する場合がある。
PS C:\> Import-Module ActiveDirectory
PS C:\> Get-ADGroupMember LargeGroup
Get-ADGroupMember : この要求のサイズ制限を超過しました。
発生場所 行:1 文字:18
+ Get-ADGroupMember <<<< LargeGroup
+ CategoryInfo : NotSpecified: (LargeGroup:ADGroup) [Get-ADGroupMember]、ADException
+ FullyQualifiedErrorId : この要求のサイズ制限を超過しました。,Microsoft.ActiveDirectory.Management.Commands.GetADGroupMember

PS C:\>
調査した範囲では、ActiveDirectory モジュールではこれを解決する方法は無い様だ。

そこで、この問題をADSIを使って解決する。
PS C:\> [DirectoryServices.DirectoryEntry]$ADSIGroup = [ADSI]("LDAP://CN=LargeGroup,CN=Some Groups,DC=domain,DC=local")
PS C:\> $members = $ADSIGroup.Members() | foreach { ([DirectoryServices.DirectoryEntry]$_).distinguishedName }
PS C:\>


二つ目の問題は、次のように一般化できる。
あるグループGとオブジェクトUに対して、UがGのメンバであるかどうかを返す。
間接的には、Get-ADPrincipalGroupMembershipを使えば解決できるが、このコマンドレットでは、G以外のグループに関しても所属関係を調べてしまう分無駄だ。
これもADSIで解決する。
PS C:\> [DirectoryServices.DirectoryEntry]$ADSIGroup = [ADSI]("LDAP://CN=LargeGroup,CN=Some Groups,DC=domain,DC=local")
PS C:\> $ADSIGroup.IsMember("LDAP://CN=user01,OU=Users,DC=domain,DC=local")
True
PS C:\> $ADSIGroup.IsMember("LDAP://CN=user02,OU=Users,DC=domain,DC=local")
False
PS C:\>