Hey, Scripting Guy!

Scripting Guys が皆さんの質問にお答えします

Hey, Scripting Guy!

TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。

詳細情報

Hey, Scripting Guy! カテゴリ別アーカイブ

Hey, Scripting Guy! 日付別アーカイブ

Hey, Scripting Guy! ダウンロード

Spacer

*

Active Directory のすべてのグループの管理者を確認する方法はありますか

Hey, Scripting Guy! Question

Scripting Guy さん、よろしくお願いします。すべての Active Directory グループと、各グループを管理するユーザーの名前の一覧を取得する方法はありますか。

-- PL

SpacerHey, Scripting Guy! AnswerScript Center

PL さん、こんにちは。皆さんのほとんどが、今月は Scripting Guys にとって忙しい月だったので、Scripting Guys は、もうそろそろ休暇を取った方が良いのではないかと考えていらっしゃることはわかっています。私たちも休暇を取りたいのですが・・・。何ですって。Scripting Guys が休暇を取るべきだとは、だれも考えていないですって。だれ一人としていないのですか。お母さん、お父さん、だれか・・・。

うーん。

ただ、いずれにしても Scripting Guys には今休暇を取る余裕はないため、かえって好都合です。というのも、2008 年冬季スクリプト競技大会がもうすぐ (2 月 15 日 〜 3 月 3 日) であり、その第 3 回スクリプト競技大会の準備のためにやらなければいけないことがたくさんあります (たとえば、皆さんに参加していただく種目を考える必要があります)。ご想像のとおり、私たちの計画は、2008 年の競技大会を 2007 年大会よりもさらに規模を拡大して、向上させることです。そので、競技にまったく新しい階級を追加しました。今年は、(スクリプトの初心者または上級者として) Perl、VBScript、および Windows PowerShell で競うことができます (そうです、Perl です)。そのうえ、どういうわけか 1 日ですべての種目を完了させる目立ちたがり屋 (どなたかはご自身でおわかりでしょう) の参加者向けにおまけの種目をいくつか用意しています (悲しいですが事実、そもそも種目を考案するのは Scripting Guys ですが、その Scripting Guys でさえ 1 日ですべての種目を完了することはできません)。また、ユーザー グループのメンバの皆さんは、引き続き注目してください。ユーザー グループ向けにちょっとした特別な "競技大会内の競技大会" を用意する可能性が十分にあります。

何ですって。賞品ですか。もちろん賞品をご用意しています (何か考案できればの話ですが)。賞品に加えて、どれか 1 つの階級 (Advanced Perl など) で 60 ポイント以上を獲得した参加者には優秀証明書が授与されます。言うまでもありませんが、どなたにもお楽しみいただけます。

ただし、それら大量の応募作品をすべてテストして採点しなければならない 2 人の Scripting Guys は除いた方がよいでしょう。この 2 人以外の皆さんにはお楽しみいただけるでしょう。

楽しい時間になるようにしましょう。

良い質問ですね。スクリプト競技大会が 2 月 15 日に始まるということを覚えておくには、どうすればいいのか、ですって。おそらく、私たちが、競技大会の開催前に何度かお知らせすると思います。また、Microsoft Outlook ユーザーは次のスクリプトを実行して、2008 年 2 月 14 日木曜日にアラームを設定することができます。

Const olAppointmentItem = 1 
Set objOutlook = CreateObject("Outlook.Application") 
Set objAppointment = objOutlook.CreateItem(olAppointmentItem) 
objAppointment.Start = #2/15/2008 8:00 AM# 
objAppointment.AllDayEvent = True 
objAppointment.Subject = "2008 Winter Scripting Games" 
objAppointment.Body = "The 2008 Winter Scripting Games begin at 8:00 AM Pacific Standard Time. " & _ 
    "Go to http://www.microsoft.com/scriptcenter/funzone/games.mspx to begin play. The Games end " & _ 
        "on Monday, March 3, 2008." 
objAppointment.Location = "TechNet Script Center" 
objAppointment.ReminderMinutesBeforeStart = 1440 
objAppointment.ReminderSet = True 
  
objAppointment.Save

こうして、すべての Active Directory グループと、それらの各グループを管理するユーザーの名前の一覧を取得します。ご精読ありがとうございました。では、また明日。

おっと、すいません。ちょっと先走りすぎてしまいましたね。すべての Active Directory グループと、それらの各グループを管理するユーザーの名前の一覧を取得するスクリプトは、次のとおりです。

On Error Resume Next 
 
Const ADS_SCOPE_SUBTREE = 2 
 
Set objConnection = CreateObject("ADODB.Connection") 
Set objCommand =   CreateObject("ADODB.Command") 
objConnection.Provider = "ADsDSOObject" 
objConnection.Open "Active Directory Provider" 
Set objCommand.ActiveConnection = objConnection 
 
objCommand.Properties("Page Size") = 1000 
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE  
 
objCommand.CommandText = _ 
    "SELECT Name, managedBy FROM 'LDAP://DC=fabrikam,DC=com' WHERE objectCategory='group'" 
 
Set objRecordSet = objCommand.Execute 
 
objRecordSet.MoveFirst 
 
Do Until objRecordSet.EOF 
    Wscript.Echo objRecordSet.Fields("Name").Value  
    Wscript.Echo objRecordSet.Fields("managedBy").Value 
    Wscript.Echo 
    objRecordSet.MoveNext 
Loop

こちらの方がもう少しいいですね。

ご覧のとおり、これは Active Directory の検索スクリプトです。これは Active Directory 検索スクリプトですから、それが意味することはたった 1 つ、今日はスクリプトについて詳しく説明しないということです。なぜでしょうか。まず 1 つには、Scripting Guys が怠けているからです (それに、だれもそう思わなくても Scripting Guys はそろそろ休暇を取るべきだからです)。しかし、さらに重要なのは、Active Directory 検索スクリプトを詳しく説明するには、1 日分の Hey, Scripting Guy! コラムだけでは足りないからです。でも、がっかりしないでください。Active Directory の検索に関して必要な情報を提供している 2 部構成の「Tales from the Script」シリーズをご用意してあります。

さらにもっとです。

: おや、どうして悲しそうな顔をしているのですか。Windows PowerShell ユーザーなんですね。Windows PowerShell ユーザーが Active Directory を検索できるかどうかに、だれも関心を持っていないと思っているのですね。いいですか、元気を出してください。Scripting Guys は、Windows PowerShell を使用して Active Directory を検索できるかどうかに関心を持っています。実際、その方法を説明する完全な記事を執筆しました。さらに、スクリプト センターのスクリプトのリポジトリで 100 を超えるサンプル スクリプトを提供しています。

だれも関心を持っていないと思っていたかもしれませんが、Scripting Guys は Windows PowerShell ユーザーに常に関心を持っています。

Active Directory の検索について詳しく説明する代わりに、少し時間を取って、グループ情報の取得に使用する SQL クエリと、その情報の表示に使用する Do Until ループについて見てみます。SQL クエリは次のようになります。

objCommand.CommandText = _ 
    "SELECT Name, managedBy FROM 'LDAP://DC=fabrikam,DC=com' WHERE objectCategory='group'"

ご覧のとおり、この SQL クエリでは、fabrikam.com ドメイン全体を検索して、Name と managedBy (グループ所有者を追跡する属性) という 2 つの属性の値を返すようにスクリプトに指示をしています。このクエリには、objectCategory プロパティの値が group であるすべてオブジェクトにデータを制限する Where 句も含まれます。これらの要素を組み合わせると、fabrikam.com のすべてのグループの名前と所有者を返す SQL クエリになります。

これは、まさに SQL クエリを使用して返す必要がある情報です。

このクエリを実行すると、要求したすべての情報を含むレコードセットが返されます。要求した情報を取得したら、レコードセットの EOF (ファイルの終わり) プロパティが True になるまで実行する Do Until ループを設定します このループ内では、次の 2 行のコードを使用して、グループ名とグループ所有者をエコー バックします。

Wscript.Echo objRecordSet.Fields("Name").Value  
Wscript.Echo objRecordSet.Fields("managedBy").Value

その後、Wscript.Echo コマンドを使用して出力に空白行を挿入し、MoveNext メソッドを使用してレコードセット内の次のレコードに移動します (MoveNext メソッドを呼び出すことを忘れないでください。もし忘れると、レコードセット内の最初のレコードの値が永久にエコー バックされることになります)。すべての処理が終わると、次のような結果が出力されます。

Finance Department Employees 
CN=Ken Myer,OU=Finance,DC=fabrikam,DC=com 
 
Finance Department Managers 
CN=Jonathan Haas,OU=Finance,DC=fabrikam,DC=com 
 
Human Resources Employees 
CN=Pilar Ackerman,OU=HR,DC=fabrikam,DC=com

こうして、すべての Active Directory グループと、それらの各グループを管理するユーザー名の一覧を取得します。ご精読ありがとうございました。では、また明日。

いいところに気が付きましたね。ご覧のとおり、サンプル スクリプトは問題なく機能し、各グループの名前と所有者が返されます。唯一の問題は、managedBy 属性ではグループ所有者がその識別名に基づいて格納されている点です。つまり次のような名前が返されます。

CN=Ken Myer,OU=Finance,DC=fabrikam,DC=com

これでも問題はありませんが、多くの場合、所有者の名前が次のように表示されたほうが良いでしょう。

Ken Myer

これは問題です。これは表示名ですが、managedBy 属性には表示名が格納されていません。

つまり運がないということでしょうか。ちょっと、Scripting Guys はもう何年も運に見放されています (何しろ、ほんの少しでも運があれば、そもそも Scripting Guys にはなっていなかったでしょうから)。ただし幸運なことに、この問題に対処するために運は必要ありません。必要なのは、次のように Do Until ループを変更することだけです。

Do Until objRecordSet.EOF 
    Wscript.Echo objRecordSet.Fields("Name").Value  
    strUserDN = objRecordSet.Fields("managedBy").Value 
    Set objUser = GetObject("LDAP://" & strUserDN) 
    Wscript.Echo objUser.displayName 
    Wscript.Echo 
    objRecordSet.MoveNext 
Loop

このループでは何が異なるかというと、まずは何も異なりません。1 行目では、元のスクリプトとまったく同じように、グループの Name 属性の値をエコー バックします。しかし、2 行目からは処理が異なります。今回のループでは、managedBy 属性の値をエコー バックする代わりに、その値を strUserDN という名前の変数に格納します。

strUserDN = objRecordSet.Fields("managedBy").Value

この作業の目的は何か、ですって。特に目的はありません。ただ、ランチまでちょっと時間をつぶしているだけです。

すみません、ほんの冗談です。Scripting Guys が行うすべての作業には必ず目的があります (Scripting Guys が行う作業の目的が適切かどうかは別問題ですが)。所有者の識別名の値を取得している理由は、その値を GetObject 関数に渡して、Active Directory の所有者のユーザー アカウントに直接バインドできるようにするためです。

Set objUser = GetObject("LDAP://" & strUserDN)

では、この作業の目的は何かというと、ユーザー アカウントにバインドすると、そのアカウントの属性値をエコー バックできます。グループ アカウントにバインドした場合、エコー バックできるのはグループ所有者の識別名だけです。というのも、(managedBy 属性を通じて) 使用可能な名前が識別名だけだからです。所有者の個々のユーザー アカウントにバインドすることで、displayName など、そのアカウントのあらゆる属性値をエコー バックできます。

Wscript.Echo objUser.displayName

なぜ displayName 属性の値をエコー バックする必要があるかというと、それによって次のような出力を取得するためです。

Finance Department Employees 
Ken Myer 
 
Finance Department Managers 
Jonathan Haas 
 
Human Resources Employees 
Pilar Ackerman

とてもすばらしいですよね。

もちろん、指定のユーザーが管理しているすべてのグループの名前を返すように、元のスクリプトを簡単に変更できます。必要な作業は、次のように、そのユーザーの識別名を Where 句に含めるだけです。

objCommand.CommandText = _ 
    "SELECT Name FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory=group' " & _ 
        "AND managedBy='CN=Ken Myer,OU=Finance,dc=fabrikam,dc=com'"

このクエリでは、Ken Myer が管理しているグループの一覧が返されます。

PL さん、これでうまくいくでしょう。冬季スクリプト競技大会 (開催期間、2008 年 2 月 15 日 〜 2008 年 3 月 3 日) がほんの数か月後に迫っていることを忘れないでください。今後それまでは、競技大会ホーム ページを定期的に確認してください。お勧めは、毎週提供する競技大会の準備に役立つアドバイスです。また、昨年の競技大会で満点を獲得した方は、「Profiles in Perfection」(英語) ページへの情報の提供をお忘れなく。簡単な自己紹介と写真を scripter@microsoft.com (英語のみ) まで電子メールでお送りください。

おっと、そして、次のことを覚えておいてください。タイガー ウッズは、2007 年のスクリプト競技大会に参加しませんでした。その結果どうなったかを考えてみてください。皆さんにはこのことを他山の石としていただければ、と思います。

何ですって。彼がいくら稼いだんですって。うわっ、それは随分な大金ですね。まあ、とにかく、スクリプト競技大会には参加してください。お金がすべてではありません。

それに、きっとタイガー ウッズは Dr. Scripto ボブルヘッド人形を持っていません。また、私たちはいくらお金をもらっても決して Dr. Scripto ボブルヘッド人形を売ることはありません。Dr. Scripto ボブルヘッド人形のようなスクリプト競技大会のすばらしい賞品は、お金で買うことはできません。大会に参加して獲得する必要があります。

タイガーウッズへの注 : 上記の記述については心配しないでください。これはすべて、編集者に追加させられた法的なたわ言です。このコラムを執筆している Scripting Guy にいつでもお問い合わせいただき、お気軽にお申し付けください。何とか手を打ってみますから。


ページのトップへページのトップへ