
TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。
詳細情報
| • | |
| • | |
| • |
![]()
Windows PowerShell を使用して、ドメインにあるすべてのコンピュータ アカウントのリストを取得する方法はありますか。
-- TE

TE さん、こんにちは。数年前、このコラムを書いている Scripting Guy は、兄弟の一人とバスケットボールをしていました。公園には 5 人しかいなかったので、2 対 2 でプレイしなくてはならず、1 人は観ているだけでした。しばらくすると、6 人目がやって来て参加してもよいかどうかをたずねました。彼は、身体が小さく、とても大人しくて控えめな男でしたが、このコラムを書いている Scripting Guy はなぜか、ひと目見て "こいつはできるぞ" と思いました。
「僕が彼をマークするよ」と Scripting Brother が言いました。
「できるかな」とこのコラムを書いている Scripting Guy は答えました。「ゾーンか何かをやるべきかもね」
「いや、そんな必要はないよ」と Scripting Brother は言いました。「彼をマークしたいんだ」
で、どうなったかって。こう考えてみましょう。Scripting Brother は、今では誰よりも、願い事は慎重にという古いことわざの本当の意味を知っています。なかなかどうして、その男は、世界の歴史で最高のバスケットボール選手になるかもしれないのです。彼は、Scripting Brother のディフェンスを簡単にすり抜けました。彼は Scripting Brother より高く飛んでリバンドを取り、ジャンプ シュートを決めました。彼は、ゲームも Scripting Brother も完全に圧倒してしまったのです。
ゲームを半分終わったところで、Scripting Brother はこのコラムを書いている Scripting Guy に言いました。「マークする相手を替えないかい。」
「いいや、やめとくよ」とこのコラムを書いている Scripting Guy は答えました。Scripting Guy は、ゲームが終了するまでにせいぜい 2、3 回しかボールに触らないような男をマークしていたのです。「僕は大丈夫だよ」
さて、確かに、Active Directory からコンピュータ アカウントのリストを取得するスクリプトを記述するのは、バスケットボールでディフェンス不可能な選手をマークするほど難しくはありません。それでもやはり、自分が何をやろうとしているのかを理解して欲しかっただけなんです、TE さん。この質問をしたのはあなただということを覚えておいてください。
$strCategory = "computer"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = ("(objectCategory=$strCategory)")
$colProplist = "name"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{$objComputer = $objResult.Properties; $objComputer.name}
実際、このスクリプトは見た目と違って全然難しくありません。問題は、かなり威圧感を与えるように見えるということです。しかし、大丈夫です。とにかく、このようなスクリプトがどう機能するかを説明しようとするのが私たちの仕事ですから。
当然のことながら、"しようとする" という部分を強調しておきます。
まず、値 computer を $strCategory という変数に代入するという、簡単なところから始めます。次に、このコード行を使用して、NET Framework クラスの System.DirectoryServices.DirectoryEntry の新しいインスタンスを作成します。このインスタンスの作成時に、他のパラメータを指定していないので、オブジェクト参照 $objDomain によって、自動的に Active Directory ドメインのルートに接続されます。簡単でしょう。
偶然にも、話していたコード行がここにあります。
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
ドメインに接続したら、System.DirectoryServices.DirectorySearcher クラスのインスタンスを作成する必要があります。これは、Active Directory 検索を実行するのに使用するオブジェクトです。オブジェクトを作成したら、次の 2 行のコードを使用して、値を DirectorySearcher SearchRoot プロパティと Filter プロパティに代入します。
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = ("(objectCategory=$strCategory)")
おわかりだと思いますが、SearchRoot プロパティは、検索を開始する場所を DirectorySearcher に指示するだけです。ドメイン全体を検索するので、SearchRoot をオブジェクト参照 $objDomain に設定します。順番に、Filter プロパティを使用すると、Active Directory で見つかった項目の特定のサブセットを指定できます。目的はコンピュータだけなので、Filter プロパティがそれらのオブジェクトだけを返すように指定します。ここで、objectCategory 属性は、変数 $strCategory と同じです (ご存知のように、これは "computer" と同じです)。
注 : Windows PowerShell を使用して Active Directory を検索する方法の詳細については、この小さいコラムではとても説明できません。しかし、Filter プロパティでは LDAP 検索構文が必要です。ここでは、おなじみの SQL スタイル構文は使用できません。詳細については、MSDN の DirectorySearcher のドキュメントを参照してください。 |
次に、検索で返される属性および属性値を指定します (いわゆる "プロパティ リスト" を指定しないと、すべての属性および属性値が返されます。これは、余分な情報が返されるだけでなく、ネットワークを渋滞させるほどのデータ量になるでしょう)。次の 2 行のコードによって、返されるプロパティ値のリストに name 属性が追加されます。
$colProplist = "name"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
プロパティ リストは、配列として構築する必要があります。どうしてこれが重要なのかおわかりでしょうか。name と cn の両方が返されると仮定します。この場合、次のような構文を使用して、2 つの値を $colProplist に代入する必要があります。
$colProplist = "name", "cn"
そうです、それが配列です。Windows PowerShell では、複数の値 (個々の値はコンマで区切られています) を変数に代入するだけで配列を作成できます。
配列を作成したら、次は PropertiesToLoad メソッドを使用して、それらのプロパティを DirectorySearcher に追加します。これを行うには、配列のすべての項目を処理する For Each ループを設定して、各項目を DirectorySearcher に追加します。
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
注 : なんですって。Windows PowerShell で For Each ループを作成する方法をご存知ないんですか。ご存知でない場合は、「Windows PowerShell の機能」をご覧ください。 |
さて、ようやく Active Directory を検索する準備ができました。これを行うには、FindAll() メソッドを呼び出して、検索で返されたデータを $colResults という変数に格納します。
$colResults = $objSearcher.FindAll()
あとは、コレクション $colResults のすべての項目 (コンピュータ) を処理する 2 つ目の For Each ループを設定するだけです。コレクションの項目 (コンピュータ) ごとにこのコード部分を使用して、項目 Properties を $objComputer という変数に格納します。これを行うのは、name だけを要求した場合でも、既定によってコンピュータの ADsPath も返され、出力が読み取りにくくなるからです。
$objComputer = $objResult.Properties
読み取りにくい出力を気にしなければ、$colResults の値をエコー バックするだけで十分です。
$colResults
コンピュータの Properties が $objComputer に格納されたらすぐにこのコマンドを使用してコンピュータ名だけをエコー バックできます。
$objComputer.name
この処理の結果、次のような出力が得られます。
atl-dc-01 atl-dc-02 atl-dc-03 atl-dc-04
そもそも私たちが望んでいたのはどれでしょう。
既に言ったように、このスクリプトは、すべての $ や中括弧、Windows PowerShell で使用しなければならないその他の見慣れない文字のせいもあるとはいえ、ちょっと複雑です。しかし、複雑かどうかにかかわらず、Windows PowerShell を使用して Active Directory を操作することは大変おもしろいので、何ができるかを今後見ていきましょう。
しかし、そうこうしているうちに、バスケットボールに出掛ける時間になりました。ふふ〜ん、大人しくて控えめな小柄な男があそこにいます。彼をマークします。いいえ、心配はしていませんよ。願い事に慎重になる必要はないってよく言いませんか。物事はいつも良い結果が出るものです。
ともかく、そんなものなんです。Scripting Brother に今度会ったら聞いてみます。