Hey, Scripting Guy!世間知らずがローカル ユーザーとグループに挑戦する

Microsoft Scripting Guys

この記事で使用しているコードのダウンロード: HeyScriptingGuy2007_04.exe (151KB)

ファイルとフォルダのセキュリティ記述子を管理する方法はありますか

信じられないかもしれませんが、 もちろん昔は Scripting Guys もそれほど賢くはありませんでした。信じられないでしょう。何ですか。信じられる、しかもそれほど昔のことではないでしょう、ですって。何をおっしゃっているんですか。いいですか、教えてあげましょう。そうですね、皆さんは、先日 Scripting Guys の著者の 1 人が新しい TV を接続しようとしたのを確かに見たでしょう。

この Scripting Guy だけは、新しい TV の取り付けはロケット科学ではないから簡単だと自己弁護しそうですが、実際はロケット科学よりも複雑です。TV の取り付け自体は 3 本のビデオ ケーブルと 1 組のオーディオ ケーブルを配線するだけですが、それに加えてビデオ、DVD プレーヤー、Xbox® などをそこに取り付ける必要があります。また、不規則な数字を "汎用" リモコンに入力して、それらのデバイスをすべて認識できるようにする作業も当然必要です。これに比べれば、人口衛星を火星の軌道に乗せることなど簡単です。

驚くべきことに、この Scripting Guy は何とかすべての接続を正確に行いました。しかし、すべての電源を入れても何も起こりませんでした。彼はきちんと各接続を 2 回も 3 回も確認しました。また、すべてのユーザー マニュアルを読んだり、見落としている情報がないかどうかをオンラインで調べたりもしました。しかし何も得ることはできませんでした。彼が MP3 プレーヤーを電子工学の神にいけにえとして捧げようとしていたそのとき、彼はケーブル ボックスから伸びているケーブルを壁のケーブル差込口に差し込むという重要な手順を行っていなかったことに気が付きました。

注 : この Scripting Guy の家にあるものをすべて接続するのがこれほど大変であるということは、この家は物であふれかえっていると思うかもしれません。実際、この Scripting Guy もそのことは認めるでしょう。しかし、新しいものを買うときの家族投票で、この Scripting Guy はいつも 2 対 0 で敗れてしまいます。読み間違えないでください、2 対 1 ではなく 2 対 0 です。どういうわけか、父親の票はこの家族投票の集計対象になる気配がまったくありません。しかも投票記録も残っていません。

あなたの疑問に対する答えはイエスです。彼は努力しました。しかし今のところ、国連はこの議会に投票監視員を派遣することを拒否しています。

もちろん今考えてみると、Scripting Guys (特に新しい TV を接続した Scripting Guy) は世間知らずでしたが、それほど間抜けだったわけではありません。たとえば、『Microsoft® Windows® 2000 スクリプト ガイド』の計画段階で、この書籍の章を考えるとき、Scripting Guys は多くの専門家の助けを借りました。落選した章の中に、ローカル ユーザーとグループの管理に関する章がありました。専門家は "ローカル ユーザーとグループの管理?" "なぜそんなことを考えるの? ローカル ユーザーとグループのことなんてだれも気にしないよ。" と言いました。

とても悔しいのですが、それ以降多くの人たちが (社内の "専門家" のような例外もありますが) ローカル ユーザーとグループに関心があることがわかりました。毎週、ユーザーをローカル グループに追加する方法、ユーザーをローカル グループから削除する方法、コンピュータのローカル管理者のパスワードを変更する方法などに関する質問が書かれた電子メールが山のように寄せられています。

確かに、スクリプト センターのスクリプト リポジトリにもこれらの作業を行う方法が示されたサンプル スクリプトがいくつかありますが、これらのスクリプトのほとんどは一度に 1 台のコンピュータしか操作しません。これでは不十分です。ユーザーが知りたいのは、この操作を複数のコンピュータに対して同時に実行する方法です。1 台のコンピュータでしかローカル管理者のパスワードを変更できないのですか、ユーザーに聞いてみてくださいよ、Scripting Guy。私たちは所有しているすべてのコンピュータ、OU 内のすべてのコンピュータ、またはすべてのメール サーバーでその操作を行う必要があるのです。おわかりでしょう、と。

スクリプト ガイドが 2003 年に発行されたことを考えると、同じような電子メール メッセージが 4 年近くの間殺到していたということになります。最近 Scripting Guy の 1 人が、"Excel® ワークシートからコンピュータ名を読み取って、各コンピュータのローカル管理者のパスワードを変更する方法を教えてほしいという質問があったよ。どうしたらいいだろう。" と言いました。

4 年間かかりましたが、ついにわかりました。図 1 に示したコードが私たちの成果です。

Figure 1 ようやく完成したコード

On Error Resume Next

Set objExcel = CreateObject(“Excel.Application”)
Set objWorkbook = objExcel.Workbooks.Open(“C:\Scripts\Test.xls”)
objExcel.Visible = True

i = 2

Do Until objExcel.Cells(i, 1).Value = “”
    strComputer = objExcel.Cells(i, 1).Value   
    Set objUser = GetObject(“WinNT://” & strComputer & “/Administrator”)
    If Err = 0 Then
         objUser.SetPassword “egTY634!alK2”
         objExcel.Cells(i, 2).Value = Now
    End If
    Err.Clear
    i = i + 1
Loop

注 : おわかりのとおり、このスクリプトを記述するのに 4 年かかったのは、記述することが大変だったからではなく、Scripting Guys が何をするのにも時間がかかるからです。ですから、Scripting Guys が毎年大みそかに行うパーティには必ず出席しましょう。次の恒例イベントはいつ行われるか (または行われることがあるのかさえも) わかりませんからね。

ここで紹介するのは、ワークシートからコンピュータ名を読み取って、各コンピュータのローカル管理者のパスワードを変更するスクリプトです。このマジックを行うために、まず簡単なことから始めます。図 2 のような、とても単純なワークシートがあるとします (ない場合は作成してください)。

図 2 変更を加えるコンピュータの一覧

図 2** 変更を加えるコンピュータの一覧 **(画像を拡大するには、ここをクリックします)

ご覧のとおり、特別なものはありません。列 1 (列 A) には、パスワードを変更する必要があるすべてのコンピュータの名前が列挙されています。列 2 (列 B) には、各コンピュータのローカル管理者のパスワードが最後に変更された日時を記録します。これにより、ローカル管理者のパスワードがすべて同期されているかどうかを簡単に把握することができます。

スクリプト自体は、まず On Error Resume Next ステートメントを使用します。通常は、わざわざスクリプトにエラー処理を含めたりしません。これは、エラー処理を記述することに反対しているわけではなく、スクリプトをできる限り短くてわかりやすくするためです。しかしここでは、On Error Resume Next ステートメントでなければなりません。これは、このスクリプトが異なる複数のコンピュータに接続するからです。いずれかのコンピュータの電源がオフになったらどうなるでしょうか。エラー処理を行っても、何も起こりません。もちろんエラーは発生しますが、スクリプトはエラーを無視して先に進むことができます。エラー処理を行わなかった場合、Scripting Guy が新しい TV の電源を初めて入れたときとほぼ同じ状況になります。つまり、何も起こりません。

次に、以下のコード ブロックを使用して、Excel.Application オブジェクトのインスタンスを作成し、その Excel インスタンスを画面に表示し、ワークシート C:\Scripts\Test.xls を開きます。

Set objExcel = CreateObject _
    (“Excel.Application”)
Set objWorkbook = objExcel.Workbooks.Open _
    (“C:\Scripts\Test.xls”)
objExcel.Visible = True

大事なことを言い忘れていましたが、カウンタ変数 i に値 2 を代入します。この変数は、ワークシートの現在の行を追跡するために使用します。

注 : i に 2 を代入するのはなぜでしょうか。答えは簡単です。ワークシートをよくご覧ください。実際のデータは 2 行目から始まっています。1 行目は単なる見出しです。

どうですか。私たちは YPbPr1 ケーブルの接続は得意ではないかもしれませんが、スクリプトについては多少知っています。

まあ、いずれにしてもときどきしか役に立ちませんが。

これで準備ができました。まず、列 1 の空のセルを検出するまで実行される Do Until ループを設定します。これは、他に何をしていても、列 1 の行だけは空にしてはならないということです。スクリプトは空の行を検出すると、データの末尾に達したと見なしてループ (スクリプト) を終了します。回避策はいくつかありますが、単にワークシート内に空の行をつくらないようにする方が簡単です。

ループ内では、まず、行 i、列 1 のセルの値を strComputer という名前の変数に代入します (1 回目のループでは、i の値が 2 であるため、行 2、列 1 のセルの値を代入します)。次に、以下のコードを使用して、変数 strComputer によって示されたコンピュータのローカル管理者アカウントへのオブジェクト参照 (objUser) を作成します。

Set objUser = GetObject(“WinNT://” & _
    strComputer & “/Administrator”)

エラーが発生した場合、このスクリプトはその時点で失敗します。たとえば、ネットワークの問題が発生したり、コンピュータの電源がオフになったり、Scripting Guy の 1 人が DVD プレーヤーの取り付けを誤って米国西部全体を停電にしてしまったりするかもしれません。このようなことが起こった場合、目的のコンピュータに接続することはできません。このため、上記のコードのすぐ後、以下のように VBScript の Err オブジェクトの値を確認します。

If Err = 0 Then

Err オブジェクトの値が 0 の場合、問題なく目的のコンピュータ (およびその管理者アカウント) に接続できたことを意味します。Err が 0 以外の場合、可能性は 1 つだけです。つまり、接続に失敗したということです。この場合、接続先のコンピュータのパスワードを変更する処理は実行しません。言うまでもなく、接続できなければパスワードを変更することはできないからです。

エラーが発生しなかった場合、以下の 2 行のコードが実行されます。

objUser.SetPassword “egTY634!alK2”
objExcel.Cells(i, 2).Value = Now

1 行目では、SetPassword メソッドを使用して、新しいパスワード (egTY634!alK2) をローカル管理者アカウントに割り当てます (もちろん、パスワードにはお子さんの名前を使用しないでください)。2 行目では、現在の日時を (VBScript の Now 関数を使用して) 行 i、列 2 のセルに書き込みます。[Password Changed] 列を更新するのは、実際にリモート コンピュータに接続してパスワードを変更できた場合のみであることに注意してください。コンピュータに接続できなかった場合、対応する [Password Changed] 列のセルは更新されません。これによって、成功した操作と失敗した操作を見分けることができます。

結局どういうことなのでしょうか。つまり、ループの処理を 1 回実行すると、ワークシートは図 3 のようになるということです。

図 3 最初のパスワードを再設定した後のコンピュータの一覧

図 3** 最初のパスワードを再設定した後のコンピュータの一覧 **(画像を拡大するには、ここをクリックします)

コンピュータ 1 に対する処理はここまでですが、次に進む前にちょっとした整理を行う必要があります。

Err.Clear
i = i + 1

上記のコードは短いですが、どちらもとても重要です (Scripting Guys があまり重要でないコードを書いているかのようですが)。最初の行では、Err オブジェクトを 0 に再設定します。エラーが発生しなかった場合、Err は既に 0 なのでこれは余分な処理になりますが、エラーが発生した場合、Err は 0 以外の値になります。この場合、Err オブジェクトを手動で再設定することがとても重要です。なぜでしょうか。それは、これがエラー オブジェクトだからです。このオブジェクトは成功を追跡せず、エラーのみを追跡します。たとえば、コンピュータ 1 で問題が発生し、接続が失敗したとします。話を続けるために、この問題が原因でエラー オブジェクトが 99 に設定されたとしましょう。

さらに、ループ処理を続行し、コンピュータ 2 に正常に接続できたとします。Err の値はどうなるでしょうか。そうです。いやが応でも、Err には 99 が設定されたままになります。これは、Err オブジェクトはエラーが発生した場合のみ変更され、エラーが発生しなかった場合は、現在の値を無期限に保持するためです。

これがそれほど重要なことなのでしょうか。当然重要です。技術的に言えば、コンピュータのパスワードを変更するのは、接続が成功した場合ではなく、Err が 0 の場合のみです。電卓を使うので、少し待ってください。はい、大丈夫でした。99 は 0 ではありません (もちろん、父親が 99 票を投じても 1 票もカウントされない Scripting Guy の家族会議の場合は除きます)。上記のことが重要である理由は、コンピュータ 2 への接続が成功しても Err は 0 にならず、Err が 0 以外の場合、スクリプトはローカル管理者のパスワードを変更するための処理を行わないからです。

つまり、Err の値が変更された場合は、その値を 0 に再設定する必要があるということです。再設定しなかった場合、それ以降スクリプトはエラーが発生したものとして処理を行います。では Err オブジェクトを 0 に再設定するにはどうすればよいでしょうか。そのとおりです。Err.Clear を呼び出せばいいのです。

次に、i の値を 1 つ増やします。なぜでしょうか。1 回目のループ処理では、i の値は 2 でした。これは、一覧の行 2、列 1 のコンピュータに接続する必要があったからです。2 回目のループ処理では、一覧の行 3、列 1 のコンピュータに接続する必要があります。i は操作する行を示す変数なので、i を 3 に設定する必要があります。ご存知のように、2 + 1 = 3 です (幸いなことに電卓をまだ終了していませんでした)。そしてようやく、ループの最初に戻ってワークシート内の次のコンピュータに対して処理を実行します。

これはすばらしい処理ですが、私たちはもう以前ほど世間知らずではないので、このスクリプトだけではユーザーから電子メールで寄せられた質問に対応できないことはよくわかっています。ユーザーは言うでしょう。"この Excel の処理はすばらしいですが、OU 内のすべてのコンピュータやテキスト ファイルに列挙されたすべてのコンピュータのローカル管理者のパスワードも変更する必要があるのです。または、コンピュータの一覧をポップアップ表示して、リスト ボックスからコンピュータを選択できたらいいと思います。それができないのであれば..." と。

まあそうあわてないでください。Scripting Guys は皆さんがお望みなら何でもいたします (その希望が叶えられるまで 4 年間待つ気があるならということになりますが)。おわかりのように、スクリプト センターでは複数のコンピュータ用のテンプレート (つまり、複数のコンピュータに対してとても簡単にスクリプトを実行できるテンプレート) がたくさん提供されています。たとえば、OU 内のすべてのコンピュータのローカル管理者のパスワードを変更する必要があるとします。問題はありません。OU 内のすべてのコンピュータに対してスクリプトを実行するためのテンプレートは、図 4 のようになります。

Figure 4 OU に対するスクリプトの実行

On Error Resume Next

Set objOU = GetObject(“LDAP://OU=Finance,dc=fabrikam,dc=com”)
objOU.Filter = Array(“Computer”)

For Each objComputer in objOU
    strComputer = objComputer.CN

    ‘ 
=====================================================================
    ‘ Insert your code here
    ‘ 
=====================================================================

    Set objComputer = GetObject(“WinNT://” & strComputer & “”)
    objComputer.Filter = Array(“User”)
    For Each objUser in objComputer
        Wscript.Echo objUser.Name
    Next

    ‘ 
=====================================================================
    ‘ End
    ‘ 
=====================================================================

Next

"Insert your code here" と書かれたセクションを見てください。必要な作業は、そのセクション内のサンプル コードを削除し、ローカル管理者のパスワードを変更するためのコード (このコラムからコピーできます) に置き換えるだけです。つまり、サンプル コードを次のコードに置き換えます。

Set objUser = GetObject(“WinNT://” & _
    strComputer & “/Administrator”)
If Err = 0 Then
    objUser.SetPassword “egTY634!alK2”
End If
Err.Clear

このサンプル コードだけでは結果は記録されませんが、そのためのコードは簡単に追加できます。サンプル コードを置き換え、いずれかの OU を指定するように接続文字列 LDAP://OU=Finance,dc=fabrikam,dc=com を変更するだけです。

実は、これらのテンプレートは 1 年以上も前から提供されています。提供したときは、これまでスクリプト センターで提供したものの中でも人気が高いスクリプトになるのではないかと思っていました。しかし私たちが間違っていました。スクリプトを複数のコンピュータに対して実行する方法に関する質問は毎日のようにたくさん寄せられますが、これらのテンプレートはほとんど使用されるようになりません。どのユーザーもこれらのテンプレートの存在を知らなかったのだと思います。しかし、これで覚えましたね。場所もお教えしておきましょう。microsoft.com/technet/scriptcenter/scripts/templates です。今までだれもこれらのテンプレートを使わなかったのは、このせいかもしれませんね。

今や Scripting Guys は以前ほど世間知らずではなくなりましたが、以前ほど間抜けでも不器用でもなくなったでしょうか。その疑問には、次のようにご説明しておきましょう。少し前に Scripting Guys の 1 人は、週末を使って家の周りのものを整理することにしました。月曜日に仕事に来たとき、彼は親指を強打して出血が止まらなくなっており、足にも大怪我を負っていました。

考えてみると、これはそれほど悪いことではありませんでした。少なくとも Scripting Guy にとっては。

Microsoft Scripting Guysマイクロソフトの仕事をしています、というよりもマイクロソフトにより雇われています。野球をプレイしたり監督したり観戦したり (または他のさまざまな活動を) しているのでない限り、彼らは TechNet スクリプト センターを運営しています。詳細については、https://www.microsoft.com/japan/technet/scriptcenter/default.mspx を参照してください。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; 許可なしに一部または全体を複製することは禁止されています.