
TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。
詳細情報
| • | |
| • | |
| • |
![]()
Scripting Guy さん、よろしくお願いします。特定のフォルダーに新しく作成されたサブフォルダーを監視する方法はありますか。WMI イベントで、新しいファイルを検出できることは知っていますが、同じ構文を使用しても新しいフォルダーを検出することができません。
-- WS

WS さん、こんにちは。今日のコラムを始める前に、WS さんに質問があります。あなたは今日のコラムを読んでいますか。今日のコラムを読めていない場合、このコラムを執筆している Scripting Guy (厳密には、このコラムを執筆していた Scripting Guy) は、このコラムの執筆を放棄することにしたということになります。
一方、今日のコラムを読めている場合は、2 つの可能性があります。シアトル地域では予報に反して今週末に雪が降らなかったか、だれかがシアトル地域で雪が降ったという理由で仕事を放棄するのはいかがなものかと、このコラムを執筆している Scripting Guy を説得したということです。特に、Scripting Guy の息子が 8 月から大学生になることを考えると、後者の意見は当然だと思います。
4 月だというのにシアトルで雪が降るというのは一体どういうことでしょうか。金曜日の朝、このコラムを執筆している Scripting Guy が、このコラムを執筆したとき (皆さんが、今現在、このコラムを読めているかどうかはわかりませんが)、シアトル地域では雪が降るという予報でした。MSNBC によると、金曜日の夜には、150 m の積雪量が見込まれるということでした。また、シアトル地域の北部では、金曜日の夜から土曜日の朝にかけて、みぞれ交じりの雪が降り、スノーホーミシュ郡とスカジット郡の北部では、10 cm 程度の積雪があるという予報でした。
それに加えて、空気は冬のように冷たく、最低気温が -1 度、最高気温がたった 5 度という予報です。
正直なところ、このコラムを執筆している Scripting Guy は、この予報を見た瞬間、もうたくさんだと思いました。シアトルで 4 月 18 日 (または、4 月 19 日) に本当に雪が降ったら、彼は、すぐに仕事を辞めて、4 月 18 日に雪が降らないどこか別の土地に引越すつもりでした。どこに引っ越すつもりだったのか、ですって。そうですね。特に決めていませんでした。何しろ、彼は、シアトルは 4 月 18 日に雪が降らない地域だと思っていましたから。シアトルより暖かい街に移り住んだ後はどうするつもりなのか、ですって。うーん。それについても特に決めていませんでした。ですが、システム管理スクリプトに関する日刊コラムを執筆する仕事を探すのは、どれくらい大変なことか考えてもみてください。
とにかく、今日のコラムを読めていないのであれば、その理由はおわかりですよね。このコラムを執筆している Scripting Guy は、シアトルよりも暖かくて快適な街に移り住んだということです。
たとえば、南極大陸とか。
ですが、シアトル地域では、雪は降らず、雨と -1 度という天候に見舞われるだけだったという可能性もわずかながらあります。その場合、このコラムを執筆している Scripting Guy は、おそらくシアトルよりも暖かい街に逃亡することはないでしょう。ということは、結論は 1 つ。皆さんが、このコラムを読んでいて、彼は、皆さんに何かしらの情報を提供する必要があるということです。
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE " _
& "TargetInstance ISA 'Win32_SubDirectory' and " _
& "TargetInstance.GroupComponent= " _
& "'Win32_Directory.Name=""C:\\\\Scripts""'")
Do While True
Set objEventObject = colMonitoredEvents.NextEvent()
Wscript.Echo objEventObject.TargetInstance.PartComponent
Loop
注: とは言うものの、事態は、このコラムを執筆している Scripting Guy が言うほど悪くはありません。たとえば、日曜日の予報は「せいぜい通り雨か吹雪」です。ほらね。通り雨か吹雪だけですよ。たいしたことじゃありませんね。 |
そうですね。少し暖を取るために、このスクリプトのしくみをご説明しましょう。WS さんが言うように、ファイルの作成状況を監視するスクリプトは、フォルダーの作成状況を監視するのには使用できません。ただし、よく似たアプローチは使用できます。必要なのは、新しいファイルではなく、新しいフォルダーを探していることを指定することだけです。言うまでもありませんが、それがまさに今回実行したことです。
ご覧のとおり、まずローカル コンピューターの WMI サービスに接続します。リモート コンピューター上で作成されたフォルダーを監視するのにも、この同じスクリプトを使用できるのか、ですって。こう言えばわかっていただけるでしょうか。この同じスクリプトを使用して、リモート コンピューター上で作成された新しいフォルダーを監視できる可能性は、4 月に雪だるまを作れる可能性と同じくらいです。
つまり、残念なことですが、この同じスクリプトを使用して、リモート コンピューター上で作成されたフォルダーを監視することは可能です。その場合に必要な作業は、リモート コンピューターの名前を strComputer 変数に代入するだけです)。以下に例を示します。
strComputer = "atl-fs-001"
WMI サービスに接続するのは簡単です。ですが、難しい (少なくとも見た目に難しい) のは、次の処理です。
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE " _
& "TargetInstance ISA 'Win32_Subdirectory' and " _
& "TargetInstance.GroupComponent= " _
& "'Win32_Directory.Name=""C:\\\\Scripts""'")
ここでは、イベント サブスクリプションを作成しています。つまり、これは、C:\Scripts フォルダーに新しいサブフォルダーが作成されたときに通知を受け取るように指定しているクエリです。それには、__InstanceCreationEvent クラスの新しいインスタンスが作成されると、(10 秒以内に) 通知を要求する ExecNotificationQuery を作成します (このクラスの新しいインスタンスは、コンピューター上で新しい WMI オブジェクトが作成されるたびに作成されます)。
でも待ってください。ここには落とし穴があります。まず、通知が必要なのは、新しいインスタンスが、Win32_Subdirectory クラスのメンバーである場合にのみです。つまり、このクラスのメンバーに限定することで、新しいフォルダーが作成されたときにのみ通知を受け取るようにすることができます。また、C:\Scripts フォルダーに新しいサブフォルダーが作成されたときにのみ通知を受け取るようにする必要もあります。
注: なぜ C:\Scripts を C:\\\\Scripts と記述したのか、ですって。今日は、この詳細については説明しません。詳細については、WMI イベントとイベント処理を取り上げている Webcast (英語) を参照してください。 |
イベント サブスクリプションを構成したら、残りの処理は簡単です。まず、永久に実行する Do ループを設定します。C:\Scripts フォルダーの監視をやめる唯一の方法は、スクリプト自体を終了することです (今日のスクリプトは、コマンド ウィンドウでスクリプトを実行し、起動には CScript スクリプト ホストで実行する必要があることをお知らせするのに丁度良いタイミングですね)。この永久ループでは、次のコード行を使用して、スクリプトに対して、イベント通知を受け取るまで何もせず、じっと待機するように指示しています。つまり、C:\Scripts フォルダーに新しいサブフォルダーが作成されるまで、スクリプトが、このコード行でブロックされるようにしています。
Set objEventObject = colMonitoredEvents.NextEvent()
C:\Scripts フォルダーに新しいサブフォルダーが作成されたらどうなるのか、ですって。その場合は、新しく作成されたフォルダーの PathComponent プロパティをエコーバックします。その結果、次のような情報が出力されます。
\\ATL-WS-001\root\cimv2:Win32_Directory.Name="c:\\scripts\\New Folder"
この出力をもう少しきれいな状態にしたい場合は、次の Do ループを使用すると、フォルダーのパスが少しきれいな状態になります。
Do While True
Set objEventObject = colMonitoredEvents.NextEvent()
strNewFolder = objEventObject.TargetInstance.PartComponent
arrNewFolder = Split(strNewFolder, "=")
strNewFolder = arrNewFolder(1)
strNewFolder = Replace(strNewFolder, "\\", "\")
strNewFolder = Replace(strNewFolder, Chr(34), "")
Wscript.Echo strNewFolder
Loop
このループ処理により、出力は、次のような状態になります。
c:\\scripts\\New Folder
どちらにしても、通知を受け取って、情報を画面に出力すると、スクリプトはループの先頭に戻り、次のイベントが発生するまで待機します。
このスクリプトは問題なく動作しますが、C:\Scripts フォルダーの直下にサブフォルダーが作成されたときにのみ通知される点に注意してください。C:\Scripts\Test フォルダーに新しいフォルダーを作成した場合、このスクリプトは、新しく作成したフォルダーを通知してくれるのか、ですって。残念ながら、そのようなことはありません。一度に監視できるのは 1 つのフォルダー レベルのみです。確かに、新しく作成される Win32_Directory クラスの全インスタンスを監視することは可能です。何しろ、このようにすれば、コンピュータ上でフォルダーが新しく作成された場合に、そのことが通知されますよね。ですが、残念ながら、この方法ではうまくいきません。コンピュータ上の任意の場所で作成された新しいフォルダを監視するクエリは負荷が高すぎると見なされ、次のようなエラーが返されます。
SWbemServicesEx: クォータ違反です
理論上は、この問題の回避策はあります。詳細については、このサポート技術情報の記事を参照してください。ただし、基本的には、一度に 1 つのフォルダーしか監視できません。そのため、クエリでフォルダーのパスを指定する必要がありました。
今日は時間切れです。もしかすると、時間切れは今日に限ったことではないかもしれませんが。このコラムを執筆している Scripting Guy が、このコラムの仕上げに取り掛かっているとき、外の気温は 2 度で、雨が降っていました。これは 4 月 18 日に本当に雪が降るということなのか、ですって。正直なところ、それは固いでしょう。何しろ、Scritping Guy の息子は、金曜日の 6:30 PM から野球の試合が予定されています。少しの雪と身を切るような寒さがなければ、シアトルの野球らしくないですよね。
まあ、Hey, Scripting Guy コラムを執筆するのは楽しかったですよ。