[ADSI:ADODB]AD から 1000 件以上のユーザ オブジェクトをクエリすると、W2K8 以降から 80072023 などが発生することがある Ver1.1

本日は、Windows Server 2008 / Windows Vista 以降の端末上で、ADODB をつかって AD から 1000 件以上のユーザ オブジェクトをクエリすると、80072023 (ERROR_DS_SIZELIMIT_EXCEEDED) や On Error Resume Next 指定を用いている場合は実装によって無限ループなど予期しない可能性が発生するという件についてご報告いたします。

【問題の概要】
Windows Server 2008 環境にて ADODB +  On Error Resume Next 指定を用いて 1000 件以上ユーザオブジェクトが存在する Active Directory 上からユーザ オブジェクトを Page Size を指定しないでクエリすると、結果セットのループ参照実装でビジーループとなり CPU 使用率が 100 % になる。一方、Windows Server 2003 上で実施しても発生しない。
なお、この現象が発生している状態で On Error Resume Next 指定をはずすと、エラーが発生していることが確認できる。

エラーの一例 :
80072023 (ERROR_DS_SIZELIMIT_EXCEEDED)

【原因】
ADSI を用いて 1000 件以上のレコードを取得する場合、通常は ADODB.Command の Page Size プロパティの設定値を 1 回の処理の際の参照範囲(レンジ)として参照動作が設定する必要があります。Page Size を指定せずに 1000件以上の大容量データを扱い、この制限を受けた際に、データが途中で分断され、結果データの終端をあらわす EOF 値の状態が想定しない状況になる可能性があります。
この現象は、Active Directory 上のユーザ オブジェクト数が 1000 件以上であるかどうかに起因するものとなります。
こうした条件になりうるクエリを On Error Resume Next を指定して実行しますとこのエラーが無視され、結果的にデータ中の EOF 値が適切ではない状況となっているにも関わらず処理が続行されてしまった結果、ループが異常動作するなどの状況になるなど、予期しない動作結果になる可能性が懸念されます。なお、Page Size に1000を指定すると 1000件単位で結果セットを再参照し、PageSize を指定しない場合は継続レコードが存在していても 1000件までしか返されません。

なぜ Windows Server 2003 ではおきないのか
Active Directory のプログラミング インターフェース (ADSI) の検索を行うインターフェースとして、IDirectorySearch があります。
この IDirectorySearch インターフェースは、1000 件以上の結果セットを扱う際、それ以降は SIZE_LIMIT_EXCEEDED を返します。1000 件以上の結果セット以降は範囲を指定して取得いただく必要があります。
ADODB を用いた検索に関しても、後述の Scripting Guy のコンテンツにございますように、Page Size 1000 までの検索を行うことが想定されています。
ところが実際には、Windows XP / Windows Server 2003 までの実装では ADODB を用いて検索を行う際は、1000 件以上の結果セットを扱う場合もエラーにならないような実装になっておりました。つまり、元々 1000 件単位で取り扱うように想定されていたオブジェクトであるにもかかわらず正常動作してしまっている状況であったということとなります。

そこで、Windows Vista / Windows Server 2008 以降より動作に見直しが入り、結果として正式に ADODB に関して修正が施され、正式に本来想定されていた IDirectorySearch と同じ動作に変更されました。

【対処方法】
まずは On Error Resume Nextを注釈化等により一旦無効化していただき、異常動作時にループ処理内でエラーが発生していないか、ご確認ください。
その後、以下のスクリプトを実施し、データが取得できるかお試しください。
データが正常に取得できる場合は、下記スクリプトのように実装を変更いただく必要がございます。

<参考資料>
すべてのユーザー アカウントを取得できないのはなぜですか
https://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/aug04/hey0824.mspx

上記ページのコード例では、Page Size = 1000 を指定した場合 1000 件以上のデータだった場合自動的にループ内ですべてのデータを取得してくるような実装となります。

※エラーについて
環境やデータの状況などによってそれぞれ違うエラーコードで発生する可能性はありますが、無限ループが発生しうる状況であることなどは変わりませんので、いずれにせよ実装による回避を取っていただく必要があります。

(WMI Programming Support Team - June 21, 2010)