
TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。
詳細情報
| • | |
| • | |
| • |
![]()
Scripting Guy さん、よろしくお願いします。Netsh.exe を使用して DHCP サーバーから情報を返すスクリプトがあります。その後、返された情報はすべてテキスト ファイルに書き込まれます。これは優れたスクリプトですが、データを解析し、その情報に含まれているすべての IP アドレスを取得しなければなりません。テキスト ファイルから IP アドレスのみを取得するスクリプトを作成する方法はありますか。
-- MJ

MJ さん、こんにちは。Scripting Guys がスクリプトに関するコラムをなぜ毎日執筆しているのか、多くの人が不思議に思っているようです。その方々からこのような質問を受けます。「新しいコラムを毎日執筆しなければいけないのは面倒になりませんか。新しいアイデアや執筆テーマを考え出すのは大変ではないですか。Scripting Guy の Jean Ross のように怠けて、日刊ではなく月間のコラムを執筆する方が楽ではないですか」と。
言うまでもなく、これらの質問の答えはすべて「はい」です。毎日コラムを執筆するのは面倒ですし、新しいアイデアや執筆テーマを考え出すのは大変ですし、Scripting Guy の Jean Ross のようになりたいです (彼女のようになりたくない人がいるでしょうか)。では、毎日欠かさず Hey, Scripting Guy! コラムを執筆し続けている理由をご説明しましょう。
そうですね、Scripting Guy の Jean Ross にあらゆる点で勝ちたいというのが理由の 1 つです (Jean Ross、実績を見てみなよ。Hey, Scripting Guy! のコラムは 781、Sesame Script のコラムはわずか 26 だよ)。しかし、さらに重要な理由は、毎日欠かさず新しいコラムを公開すると、システム管理のスクリプトに関して皆さんの質問や悩みに対処することができるということです。
その事実はさておき、日刊のコラムは Scripting Guys のあらゆる行動を厚かましく売り込む場でもあります。たとえば、TechEd IT Forum 2007 に参加するためにスペインのバルセロナに出張に行くというようなことです。TechEd IT Forum 2007 自体は、次のように控え目に紹介しています。
マイクロソフトが主催するの最高のヨーロッパ カンファレンスです。このカンファレンスは、IT プロフェッショナルに技術トレーニングを提供し、マイクロソフトのインフラストラクチャ製品やテクノロジによって安全に接続されたエンタープライズ環境を構築、計画、展開、管理するための情報とコミュニティ リソースを提供することを目的としています。
納得させられました。
ご想像のとおり、Scripting Guys は、この出張を楽しみにしています。というのも、カンファレンスに出席するために国外に行くのはこれが初めてだからです (もちろん、Scripting Guys が帰国できるかどうかについては未定です)。Scripting Guys の Jean Ross と Greg Stemp は、コンベンション センターの Ask the Expert セクションのあるブースを受け持っています。Greg は連日そのブースにいる予定ですが、Jean は 1 度姿を見せたらそれっきりでしょう (編集者注 : 少なくとも Jean は会場には姿を表すでしょう。Greg はオーランドで開催された TechEd 2007 で一度も姿を見せませんでしたが)。皆さんとおしゃべりしたり、質問に回答したりすることはできるのか、ですって。もちろんです。『Dr. Scripto’s Fun Book』の何百冊ものコピーや、大量の Dr. Scripto ボブルヘッド人形を配るのか、ですって。もちろんです。巨大なダーツボードに向かってダーツを投げることはできるのか、ですって。Greg は「はい」と答えていますが、Jean は、・・・。ええと、何でもありません。Greg が新しいアイデアを思い付いたときの Jean の発言を記載することは禁じられています。
とにかく、TechEd IT Forum への参加登録をしていない方は、まだ十分間に合いますので、ぜひご登録ください (※TechEd IT Forum 2007 は終了しました) 。ご自分の登録をしない場合は、Scripting Guys の登録をしてください。というのも、バルセロナに Scripting Guys を行かせても結局だれも会場に姿を見せることがなかった場合に、その全費用を支払ってもらった理由を上司に説明しなければならないという状況は避けたいのです。
それに、スクリプトの世界は私たちに借りがあります。テキスト ファイルから IP アドレスを取得できるスクリプトの記述方法を説明したのは私たちですよね。
おや、次のようなスクリプトをお見せしていませんでしたっけ。では、ここでご紹介します。
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)
strSearchString = objFile.ReadAll
objFile.Close
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Global = True
objRegEx.Pattern = "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
Set colMatches = objRegEx.Execute(strSearchString)
If colMatches.Count > 0 Then
For Each strMatch in colMatches
Wscript.Echo strMatch.Value
Next
End If
スクリプトのしくみについて説明する前に、MJ さんのテキスト ファイルの内容をお見せします。このファイルは次のような状態になっていて、Netsh.exe で取得 (および書式設定) されたデータを使用しています。
========================================================================== Scope Address - Subnet Mask - State -Scope Name -Comment 192.168.120.0 - 255.255.255.0 - Active -New York, Class C - New York, NY C Total No. of Scopes = 1
ご覧のとおり、このファイルには 192.168.120.0 と 255.255.255.0 という 2 つの IP アドレスが含まれています。
注 : 厳密に言うと、255.255.255.0 はサブネット マスクです。スクリプトでは、この値を返す必要がある場合と必要がない場合があります。このスクリプトでは、サブネット マスクが返されます。スクリプトからサブネット マスクが返されないようにする場合はどうすればよいでしょうか。慌てないでください。その方法は後でご紹介します。 |
ですが、最初にやるべきことからやりましょう。まず、ForReading という名前の定数を定義して、その値を 1 に設定します。この定数は、テキスト ファイルを開くときに必要になります。定数を定義したら、次のように Scripting.FileSystemObject のインスタンスを作成し、OpenTextFile メソッドを使用して C:\Scripts\Test.txt ファイルを読み取り用として開きます。
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)
ファイルを開いたら、ReadAll メソッドを使用してファイル全体の内容を読み取り、その内容を strSearchString という名前の変数に格納します。
strSearchString = objFile.ReadAll
その後、Close メソッドを呼び出してファイルを閉じます。これで完了です。
テキスト ファイルでの作業は完了ですが、IP アドレスの取得に関しては、まだ少し作業が必要です。でも、大丈夫です。Scripting Guys は少し大変な仕事に怯んだことはありませんから。
注 : 念のために言っておきますが、実際に大変な仕事をしたことがあるわけではありません。ただ、そのような仕事に怯んだことがないだけです。 |
MJ さんの電子メールに書いてあるように、あらゆる IP アドレスが取得される可能性があります。つまり、すべての IP アドレスが 192.168 で始まるとは限りません。では、このようにさまざまな IP アドレスがあることで、IP アドレスの抽出処理が複雑になるのでしょうか。信じられないかもしれませんが、複雑にはなりません。少なくとも、スクリプトで正規表現を使用する場合はそうです。
今日は正規表現の理論について説明しません。詳細については、偉大なる故 Dean Tsaltas が執筆した Webcast「String Theory for System Administrators: An Introduction to Regular Expressions」(英語) を参照してください。
注 : 厳密に言うと、Dean は実際には亡くなっていません。カナダに引っ越しただけです。でも、ほとんど同じことですよね。 |
カナダの忠実な読者のみなさんへ : ほんの冗談です。Scripting Guys はカナダに何の反感も持っていません。それどころか、カナダ出身の親友も何人かいます。 たとえば、どんな人かですって。うーん、ええと・・・。偉大なる故 Dean Tsaltas がそうです。 |
とにかく、スクリプトで正規表現を使用するには、まず次のように VBScript.RegExp オブジェクトのインスタンスを作成する必要があります。
Set objRegEx = CreateObject("VBScript.RegExp")
VBScript.RegExp オブジェクトを作成したら、Global プロパティを True に設定します。これにより、正規表現オブジェクトに、検索文字列のすべての IP アドレスを検索することが伝えられます (Global プロパティを True に設定しないと、最初の IP アドレスの検出後にスクリプトが停止します。言うまでもなく、ファイルに複数の IP アドレスが含まれている場合は問題になります)。
では、次の行に移りましょう。
objRegEx.Pattern = "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
実は、Pattern プロパティは求めている値を表します (この場合は、IP アドレスです)。この暗号のようなパターンの意味については、この後すぐに説明します。しかし、その前に、IP アドレスの性質について少し考えてみましょう。IP アドレスとは何でしょうか。通常、IP アドレスは次のような値で構成されます。
| • | 1 〜 3 桁 (値 0 〜 9) の数値とピリオド (たとえば、192.) |
| • | 1 〜 3 桁の数値とピリオド (たとえば、168.) |
| • | 1 〜 3 桁の数値とピリオド (たとえば、120.) |
| • | 1 〜 3 桁の数値 (たとえば、1) |
信じられないかもしれませんが、これは検索パターンの適切な説明でもあります。\d{1,3} という構文は、"桁を確認する。少なくとも 1 桁 (1) はあるが、3 桁 (3) 以下である" という意味です。\. という構文は、"ピリオドを確認する" という意味です。最初から最後までパターンに従うと、検索条件はどのようになるでしょうか。そうです。次のとおりです。
「1 〜 3 桁 (値 0 〜 9) の数値とピリオド、1 〜 3 桁の数値とピリオド、1 〜 3 桁の数値とピリオド、1 〜 3 桁の数値」という検索条件です。
変わってますよね。でも、これで完全にうまくいきます。
検索パターンを定義したら、次は Execute メソッドを呼び出し、ファイルの内容に対して正規表現検索を実行します。この処理を行うのが次のコードです。
Set colMatches = objRegEx.Execute(strSearchString)
Execute メソッドで検索パターンと一致するテキストが見つかった場合は、その一致するテキストは colMatches という名前のコレクションに格納されます。つまり、colMatches コレクションの Count プロパティの値が 0 より大きいかどうかを確認するだけで、IP アドレスがファイルに含まれているかどうかを確認できます。
If colMatches.Count > 0 Then
Count プロパティの値が 0 より大きい場合、For Each ループを設定して、コレクションのすべての項目をループ処理します。このループで行っている処理は、一致する Value プロパティ (つまり、検索パターンと一致するテキスト) を単にエコー バックしているだけです。
Wscript.Echo strMatch.Value
MJ さんのサンプル データセットに対してこのスクリプトを実行すると、どのような結果が返されるかというと、次のような結果です。
192.168.120.0 255.255.255.0
サブネット マスクを含めたくない、ですって。問題ありません。その場合に必要な作業は、For Each ループに If Then ステートメントを追加し、255 で始まるすべての IP アドレスを除外するだけです。この処理は、次のように Left 関数を使用して、値の最初の 3 文字が 255 と等しいかどうかを確認することによって実現できます。
For Each strMatch in colMatches
If Left(strMatch.Value, 3) <> "255" Then
Wscript.Echo strMatch.Value
End If
Next
この変更したスクリプトを実行すると、次のような結果が得られます。
192.168.120.0
さようなら、サブネット マスク。
そして、こんにちは、バルセロナ。バルセロナで開催される IT Forum (2007 年 11 月 12 〜 16 日) に来場するご予定の場合は、電子メール (英語のみ) でお知らせください (そして Ask the Experts セクションにお立ち寄りください)。そうそう、バルセロナでお勧めのレストランや楽しい遊びをご存知でしたら、それについてもお知らせいただければさいわいです。何しろ、Scripting Guy の Jean Ross でも食事を取らなければいけないのですから。
まあ、どうせ 1 か月に一度ですけどね。