2011/06/11

Active DirectoryをPowerShellで管理

作業メモ。

今までできるだけWindowsには近づかない様に仕事をしてきが、その甲斐空しく、ついにActive Directory(AD)を触らなければならなくなってしまった。
毒を食らわば皿まで、ということで、ついでにPowreShellにも本格的に挑戦することに。ちょこちょこPowerShellでは遊んでたのだが。
参考: 『Active Directory Cmdlets in Windows PowerShell

今回のシステムでは、ユーザ・グループの情報は、別システムで管理されていて、それをADへ反映する必要がある。別システム側で更新があれば、即ADへ通知してADへ反映、というのが理想だ。ADにはLDAPインターフェースも準備されている。しかし、それはできないらしい。別システム側の担当者の勉強不足が原因。
であれば、毎日別システム側で前日通知からの変更差分を作成して、それをADへ通知、それを元にADへ反映するのが効率がよい。しかし、この差分更新方式にしても、前の即時更新方式にしても、通知が届かない場合あるいは、反映処理が異常停止する場合があることを考えると、いつかそのズレを正す棚卸処理を行わなければならない。
実行時間が許すならば、棚卸処理と差分更新処理を二つ準備するよりは、棚卸処理のみ書き、毎日棚卸処理を実行するのも一つの手だ。別システム側から見ても、差分データを送るのと、全データを送るのとでは、むしろ前者の方がコストが高い場合もある。
ということで、棚卸処理のみで行くことにした。

棚卸処理で難しいのは、グループに関する所属関係の変更だ。ユーザに対して所属グループが列挙されているようなデータを元にすると、所属関係が変更になったとき、新データからは、前に所属していたグループが判らない。ユーザから所属しているグループを得るには、次の様に実行すればよい。
C:\Users\Administrator>powershell
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.

PS C:\Users\Administrator> Import-Module ActiveDirectory
PS C:\Users\Administrator> $u = Get-ADUser -Identity U0000000
PS C:\Users\Administrator> Get-ADPrincipalGroupMembership -Identity $u | select Name

Name
----
Domain Users
G0000001
G0000003


PS C:\Users\Administrator>

実際に実行していると、Get-ADPrincipalGroupMembershipの実行に時間が かかっているように感じられる。計測してみよう。
C:\Users\Administrator>powershell
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.

PS C:\Users\Administrator> (Measure-Command {Import-Module ActiveDirectory}).TotalSeconds
0.8516534
PS C:\Users\Administrator> (Measure-Command {$u = Get-ADUser -Identity U0000000}).TotalSeconds
0.0352089
PS C:\Users\Administrator> (Measure-Command {Get-ADPrincipalGroupMembership -Identity $u}).TotalSeconds
0.6945307
PS C:\Users\Administrator>
実際、Get-ADUserの20倍程時間がかかっている。これはおそらく、グループからユーザへのリンクは用意されているが、逆のグループからのユーザのリンクは存在しておらず、ユーザから所属するグループを調べるには、グループを総なめしてるからだと考えられる。←これは間違いでした。

逆に、グループから所属メンバを得るには、次の様に実行する。
PS C:\Users\Administrator> $g=Get-ADGroup -Identity G0000003
PS C:\Users\Administrator> Get-ADGroupMember -Identity $g | select Name

Name
----
U0000000
U0000001
U0000002
U0000006
U0000444


PS C:\Users\Administrator>

実行時間を計測してみよう。
PS C:\Users\Administrator> (Measure-Command {$g=Get-ADGroup -Identity G0000003}).TotalSeconds
0.0057593
PS C:\Users\Administrator> (Measure-Command {Get-ADGroupMember -Identity $g}).TotalSeconds
0.2843582
PS C:\Users\Administrator>
意外な事に、Get-ADGroupMember の実行に時間がかかっている。これは、グループのメンバをリンクからたどってオブジェクトを生成しているからかもしれない?確かに時間はかかっているが、前のGet-ADPrincipalGroupMembershipに比べると、返されるオブジェクト数に大差ないのに 、実行時間は半分以下でしかない。

以上の推測が正しいとすると、グループ数に比例してGet-ADPrincipalGroupMembershipの実行時間が増加すると考えられる。

もしそうでなかったとしても、一般に、ユーザ数は、グループ数より多いので、ユーザ数分の繰り返しを実行するより、ユーザ数分のループより、グループ数分のループの方が実行時間は短いはずだ。

結論として、ユーザに対してループして、その所属関係を変更するのではなく、グループに対してループして、その所属関係を変更する方が実行時間が短くなるはずだ。

0 件のコメント: