Hey, Scripting Guy!

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

Hey, Scripting Guy!

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

詳細情報

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

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

Hey, Scripting Guy! ダウンロード

Spacer

*

セキュリティ イベント ログから一意のユーザーの一覧を取得する方法はありますか

Hey, Scripting Guy! Question

Scripting Guy さん、よろしくお願いします。セキュリティ イベント ログから一意のユーザーの一覧を取得する方法はありますか。

-- KM

SpacerHey, Scripting Guy! AnswerScript Center

KM さん、こんにちは。ご質問にお答えする前に、別の読者からいただいた次の質問に回答しておくべきでしょう。

Scripting Guy さん、よろしくお願いします。月曜日はどうしたのですか。

私は先週 1 週間休暇を取っていたので、Hey, Scripting Guy! アーカイブを確認したのですが、先週は 4 日間しかコラムが公開されなかったことを知りました。

"楽しいときは時間が早く過ぎる" (カエルの場合は、"ハエを食べているときは楽しい") という格言はよく知っていますが、うるう年以外の年に暦の調整があったことは知りませんでした。新聞では発表されていません。ネブラスカ大学の A.D (ネブラスカでは "教皇" として知られています) の解雇に関する話で持ちきりだったので、発表されなかったのかもしれません。

私のお気に入りのインターネット検索エンジンを使用しても、月曜日のコラムは見つからないでしょう。

何があったのですか。

-- TP

TP さん、こんにちは。失われた月曜日の真相をご説明しましょう (ところで、すばらしい投書ですね。コラムに関する投書がコラム自体よりおもしろく、すばらしいのは少し悲しむべきことですが)。実は、一時的ではありましたが、先週の月曜日は実際にコラムを公開しました。しかし、公開後間もなく、削除しなければならなくなりました。その理由は、月曜日のコラムでサードパーティ ソフトウェア企業の名前を挙げたのですが、その企業への言及をすべて削除して、記事を書き直すように要求されたためです。

: でも、たいしたことではありません。というのも、800 本以上のコラムを執筆したら、遅かれ早かれきっと、だれかが異議を唱えるコラムを執筆することになるでしょうから。しかし、これまでに執筆した他のいくつかのコラムを考えると、異議を唱えられたのが、このコラムだったことにただ驚いています。

ご参考までに、Scripting Guys は、そのソフトウェア会社に対してそれほどひどい仕打ちをしたり、辛らつな意見を述べたりはしていません。それどころか、その会社の良いところをたくさん書きました (何しろ、Scripting Guys ほど頻繁にトラブルに巻き込まれる立場にあれば、今以上敵を作るわけにいきませんから)。とは言うものの、その要求に応じ、コード (およびそのコードのしくみの説明) 以外のすべての記述をコラムから削除して、そのコラムをもう一度公開しました。つまり、実際に、ここで問題になっている月曜日が存在しただけでなく、そのことを実証する月曜日のコラムもあるということです。

では、TP さんの気が変になったりはしないのかというと、TP さんはネブラスカ州にお住まいですから、それはわかりません。

: 取り急ぎ、ネブラスカは昔から Scripting Guys の大好きな州だということを付け加えておきます。

そうですね。他の全 49 州と同じくらい大好きな州です。それはどういうことでしょう。デラウェア州も好きだということなのか、ですって。うーん、このことについては、また改めてお知らせしたいと思います。

とにかく、失われた月曜日の真相については、このくらいにしておきましょう。月曜日のコラムを削除する前に読んで、気分を害した方がいらっしゃいましたら、心からお詫びいたします。正直なところ、Scripting Guys は故意にだれかの気分を害するようなことはしません。もし、そうだとしたら、今日のコラムにネブラスカ大学のフットボール プログラムのことだけを書いたでしょう。

でも、そんなことはしていません。今日のコラムでは、セキュリティ イベント ログから一意のユーザーの一覧を取得する方法だけを説明します (これは、読者の方への記述というよりは、私たち自身が覚えておくために記述したまでです)。

また、あの月曜日が本当になくなってしまったと思った方がいらっしゃいましたら、ご迷惑をおかけしたことをお詫びいたします。既に述べたように、Scripting Guys は月曜日を消してなどいません。消していたら、少し皮肉なことになっていたでしょう。というのも、Scripting Guys は、主にあちこちに臨時の土曜日を設けることで 1 週間を長くするプロジェクトに取り組んでいたのですから。でも、今考えてみると、月曜日をなくしてしまう方が少し簡単だったかもしれません。やることリストに書いておきます。

しかし、今日のコラムは時空間連続体に関するものではなく、次のように、セキュリティ イベント ログから一意のユーザーの一覧を取得する方法だけを説明します。

On Error Resume Next 
 
strComputer = "." 
 
Set objWMIService = GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2") 
 
Set colEvents = objWMIService.ExecQuery _ 
    ("Select * from Win32_NTLogEvent Where Logfile = 'Security'") 
 
Set objDictionary = CreateObject("Scripting.Dictionary") 
 
For Each objEvent in colEvents 
    If Not objDictionary.Exists(objEvent.User) Then 
        objDictionary.Add objEvent.User, objEvent.User    
    End If 
Next 
 
For Each strKey in objDictionary.Keys 
    Wscript.Echo strKey 
Next

では、このスクリプトのしくみをご説明しましょう。まず、ローカル コンピュータの WMI サービスに接続します。ただし、必要な場合は、このスクリプトはリモート コンピュータに対しても同じくらい簡単に実行できます (その場合は、リモート コンピュータの名前を strComputer 変数に代入してください)。WMI サービスに接続したら、次のように GetObject メソッドを呼び出します。

GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2")

ご覧のとおり、このスクリプトに Security 特権を含めました。ここでは、Security をかっこと中かっこで囲み、winmgmts: モニカの直後に追加しています。なぜでしょうか。Scripting Guys の多くの行いとは違い、これにはもっともな理由があります。それは、この特権を含めないと、スクリプトからデータが返されないからです (エラー メッセージは表示されませんが、情報も返されません)。Security イベント ログにアクセスするときは、必ず Security 特権を含める必要があります。Security 特権を含めなかった場合、私たちが教えなかったなどとは口外しないでくださいね。

: ちょっと待ってください。「私たちが教えなかったなどとは言わないでくださいね」と言ったことは、言わないでください。というのは、皆さんにあれこれ指示を出すことや、スクリプトでできる処理とできない処理をお伝えすることでトラブルを起こしたくないためです。でも、とにかく Security 特権を使用してくださいね。本当に、一生のお願いですから。

WMI サービスに接続したら、次のコード行を使用して Security イベント ログに記録されているすべてのイベントのコレクションを返します。

Set colEvents = objWMIService.ExecQuery _ 
    ("Select * from Win32_NTLogEvent Where Logfile = 'Security'")

ここで、注意すべきことが 1 つあります。Security イベント ログのレコード数によっては、このスクリプトが完了するまでに 1 〜 2 分 (あるいはそれ以上) 時間がかかる場合があります。このコラムを執筆している Scripting Guy は、雨どいを掃除するくらいの頻度でイベント ログの記録を消去するので、セキュリティ イベント ログには 51,000 件を超えるイベントが記録されています。この環境では、スクリプトが完了するまでに 90 秒かかりました。

雨どいをもっと頻繁に掃除することが必要になりそうです。

でも、遅かれ早かれ、Security イベント ログ内のすべてのイベントのコレクションが返されます。イベントのコレクションが返されたら、次は Scripting.Dictionary オブジェクトのインスタンスを作成します。このオブジェクトを使用して、イベント ログに記録されている一意のユーザーを追跡します。これで、気合を入れて作業を開始する準備ができました。

まず、コレクションに含まれるすべてのイベントをループ処理する For Each ループを設定します。そのループ内での最初の処理として、次のコード行を実行します。

If Not objDictionary.Exists(objEvent.User) Then

ここで何をしているのかというと、イベントの User プロパティで指定されているユーザーが、既に Dictionary オブジェクトに存在するかどうかを確認しているだけです。ユーザーが Dictionary オブジェクトに存在する場合は、ループ処理の先頭に戻り、コレクションに含まれる次のイベントについて同じ処理を繰り返します。このような処理を行うのは、ここでは一意のユーザーだけが必要で、同じユーザーを 2 回追加する必要はないためです (それに、Dictionary オブジェクトでは重複する項目が許可されていません)。ユーザーが Dictionary オブジェクトに存在しない場合は、次のコード行を使用してそのユーザーを追加します。このコードでは、User プロパティの値を Dictionary 項目とキーの両方として指定しています。

objDictionary.Add objEvent.User, objEvent.User

その後、ループ処理の先頭に戻って、コレクションに含まれる次のイベントについても同じ処理を繰り返します。

ループ処理が完了したら、次のコード ブロックを使用して一意のユーザーのコレクションをエコー バックします。

For Each strKey in objDictionary.Keys 
    Wscript.Echo strKey 
Next

そうすると、次のような結果が出力されます。

NT AUTHORITY\NETWORK SERVICE 
NT AUTHORITY\LOCAL SERVICE 
NT AUTHORITY\SYSTEM 
FABRIKAM\kmyer 
NT AUTHORITY\ANONYMOUS LOGON 
FABRIKAM\packerman

さて、どうでしょう。ポーキー ピッグの言葉を引用しましょう。サードパーティのアニメの動物の言葉を引用しない場合は、それが一番です。「これで終わりだよ。ええと、人間の皆さん」とだけ言っておきましょう。

でも最後に、皆さんは、当初の月曜日のコラムで挙げた企業名を知りたくてたまらないですよね。実は、その企業は・・・。いえ、何でもありません。うっかり名前を言ってしまうことはありません。Scripting Guys は同じ過ちを繰り返しませんから (その主な理由は、いろいろな過ちを犯しているので、同じ過ちを二度も犯すことがないためですが)。ですから、企業名を言うことはできませんし、言うつもりもありません。でも、お気に入りのインターネット検索エンジンにアクセスして、ご自分で確かめることはいつでもできます。


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