Windows PowerShell文字列理論

Don Jones

目次

現実の世界での例
複雑な一致
文字列が使用されることの多い世界

私は、Tech•Ed や TechMentor などのカンファレンスで講演をする際、宣言を行う (ユーザーが Windows PowerShell などに関する要点を覚えるのに役立つ原則を発表する) のが習慣になっています。私が行った最新の宣言は、「Windows PowerShell で文字列を解析しようとしている方は、間違ったことをしようとしています。」というものです。

これは、Windows PowerShell™ はオブジェクト指向のシェルであるという私の考え方に由来しています。サービスの一覧をテキスト ファイルにダンプし、開始されているサービスを確認するためにそのテキスト ファイルを解析するというような処理を行おうとしているとしたら、必要以上の労力を使うことになります。これは、UNIX など、テキストベースの OS では有効な方法ですが、Windows PowerShell (および Windows® 自体) では、はるかに効率的な方法でオブジェクトを使用することができます。

ユーザー独自のスクリプトを使用した場合でも、書式設定コマンド、フィルタ コマンド、エクスポート コマンドなどの、シェルのさまざまなコマンドを使用してスクリプトの出力を操作できるように、書式設定されたテキストではなくオブジェクトが生成されます (スクリプトの出力としてのカスタム オブジェクトの概念の詳細については、2008 年 7 月号の Windows PowerShell コラムを参照してください)。

フロリダ州オーランドで最近開催された TechMentor で、私は、受講者の 1 人の発言によって、ほぼすべての規則には、とりわけ原則には、例外があるということを思い出しました。その発言とは、「IIS のログ ファイル内で検索を行う場合はどうですか。その場合は、テキストを解析しなければいけないのではありませんか。」というものです。

確かに、そのとおりです。Windows PowerShell はオブジェクトを扱うのに適しているかもしれませんが、さいわい、Windows PowerShell ではテキスト文字列の解析も適切に行うことができます。そう言われてみると、IIS のログ ファイル、ファイアウォールのログ ファイル、およびその他のテキストベースのログは、絶好の例ですね。

現実世界での例

私は実際、自分が勤めていた会社のために、ファイアウォールの一連のログ ファイルを解析しなければならないことがありました。従業員が不適切な Web サイトを閲覧しているのが見つかり、人事部は追跡調査の一環として、その従業員がアクセスした Web サイトの包括的な一覧を必要としていました。これを 1 日のログ ファイルから抜き出すだけでも少し困難ですが、人事部のスタッフが求めていたのは、過去数週間分の一覧を取得するという、手動で行う気にはなれない作業でした。

会社の動的ホスト構成プロトコル (DHCP) サーバーは、その従業員のコンピュータでは数か月間、同じ IP アドレス (この例では 192.168.17.54 とします) が使用されていたことを示しました。これはめったに電源を切らないデスクトップ コンピュータだったので、もちろん、これは珍しいことではありません。また、ファイアウォールのログには発信元 IP アドレスが記録されていたので、私は Windows PowerShell が役立つと考えました。

秘密は、見過ごされがちな Select-String コマンドにあります。また、正規表現 (これについては、2007 年 11 月号の Windows PowerShell コラムで説明しました) についての実用的な知識も必要です。

Select-String コマンドは、テキスト ファイルが格納されているファイル パス、および検索対象となる正規表現または単純な文字列を受け取ります。続いて、各ログ ファイル内の、正規表現または単純な文字列に一致する各行を出力します。作業を開始するにあたって、私は単純に、その従業員のデスクトップ コンピュータの IP アドレスが含まれている行をすべて取得しようと考えました。ログ ファイルの各行には、日付とタイム スタンプが含まれていました。人事部のスタッフが求めていたものは、これですべてです。

コマンドは次のとおりです。

select-string -path c:\logs\*.txt -pattern "192.168.17.54" -allmatches –simplematch

–simpleMatch パラメータは、指定したパターンが正規表現ではなく単なる単純な文字列であることを示しています。図 1 は、出力の一部を示しています。この出力をファイルにパイプすることもできます。出力には、検索対象に一致する内容が見つかったファイルの名前、および行の番号が含まれていることに注意してください。これは、ある時点で再び出力を確認し詳細を調べる場合に、非常に役立ちます。

今月のコマンドレット : Start-Sleep

1 日の長い勤務時間の途中で皆さんに必要なもの (短時間の昼寝) を提供するコマンドレットを紹介します。Start-Sleep は、短時間の休憩を提供します。休憩が与えられるのは Windows PowerShell スクリプトですが。

スクリプトで、短時間の停止が必要になるのは珍しいことではありません。たとえば、サービスを開始し、そのサービスが起動して実行されるようになるまで数秒間待ち、その後、そのサービスを使用する他の処理を実行する必要があるとします。Start-Sleep は、この動作にまさに必要なものです。たとえば、Start-Sleep 10 を実行すると、シェルは 10 秒間停止します。より厳密な制御が必要な場合は、たとえば、Start-Sleep -milli 100 を実行して 100 ミリ秒間停止することができます。Start-Sleep を使用すると、指定した時間、シェル (スクリプト、パイプライン、およびその他すべてを含みます) が完全に停止します。今度は、私が切望してきた Start-Nap (昼寝開始) コマンドレットをだれかが作成してくれるとよいのですが。

fig01.gif

図 1 Select-String コマンドの出力 (画像をクリックすると拡大表示されます)

複雑な一致

私が要求されたとおりのものを人事部のスタッフに提供した後で、人事部のスタッフは、必要なものは結局それではなかったことに気付きました。私のレポートには、207.68.172.246 (MSN® Web サイト) など、多くの IP アドレスへのアクセスが記録されていました。調査担当スタッフから次に出された要求は、特定の IP アドレス (問題となっている Web サイトの 1 つに対応する IP アドレスであると調査担当スタッフが見なしたもの) へのアクセスのみが記録されるようにレポートの対象を限定することでした。このコラムでは、調査で浮かび上がった実際の IP アドレスは公表しません。代わりに、この例では 207.68.172.246 を使用します (通常、MSN Web サイトは不適切とは見なされませんが)。

この要求は場合によってはもう少し対処が困難なものだったでしょうが、私が扱っていたログ ファイル内では、発信元 IP アドレスと宛先 IP アドレスは隣同士にあり、コンマで区切られていたので、検索文字列を "192.168.17.54,207.68.172.246" に変更して再び検索を行うだけで済みました。

しかし、より複雑なログ ファイルでは、可変データが 2 つの IP アドレスの間に格納されている可能性があるので、単純な文字列の一致はうまく機能しません。このような場合は正規表現を使用する必要があり、正規表現は単純なログ形式に対しても適切に機能するので、ここでは、正規表現を使用した方法について説明します。

正規表現内では、ピリオド文字は、任意の 1 文字を表すワイルド カードです。また、(.)* という部分式を使用して、2 つの IP アドレス (発信元 IP アドレスと宛先 IP アドレス) の間にある任意の数の文字を検索することができます。ただし、IP アドレス自体に含まれているリテラル文字のピリオドをエスケープするために円記号を使用する必要があります。

その結果、コマンドは次のようになります。

select-string -path c:\logs\*.txt -pattern "192\.168\.17\.54(.)*207\.68\.172\.246" –allmatches

今回は正規表現を使用するので、–simpleMatch パラメータを削除しました。このコマンドを実行して得られた出力では、特定の従業員のコンピュータから不適切と見なされた特定の Web サイトへのアクセスのみが表示されました。出力には、調査担当スタッフが求めていた日付とタイム スタンプの情報も含まれていました。図 2 は、上記のようなコマンドを実行した場合に得られる可能性がある出力の一部を示しています。

fig02.gif

図 2 特定のサイトへのアクセスのみを表示するように対象が限定された検索結果 (画像をクリックすると拡大表示されます)

調査担当スタッフからそこまでは要求されませんでしたが、出力を Format-Table にパイプし、Format-Table を利用して計算列を表示することもできます。ログ ファイルのファイル名、および検索対象に一致する内容が見つかった行の番号を表に含めることができます。また、一致する内容が見つかった行自体を表示することもできます。しかし、行の残りの部分 (この例では日付とタイム スタンプ) のみが表示されるように、シェルを使用して、正規表現に一致した箇所を空の文字列に置き換えることもできます。これは高度な処理ですが、これを紹介すると、Windows PowerShell を使用して次のように 1 つのコマンド ラインで文字列データを操作し大幅にカスタマイズされた出力を生成する方法を示すことができます。

select-string -path c:\logs\*.txt -pattern "192\.168\.17\.54(.)*207\.68\.172\.246" -allmatches | ft filename,linenumber,@{"Label"="Time"; "Expression"={$_.line.replace ($_.matches[0],"")}} –auto

図 3 は、最終結果がどのようなものになるかを示しています。

fig03.gif

図 3 Select-String コマンドの書式設定された出力 (画像をクリックすると拡大表示されます)

文字列が使用されることの多い世界

オブジェクト指向という性質は Windows PowerShell の最大の強みの 1 つであることは自信を持って宣言できます。とはいえ、オブジェクトを使用できない場合もあります。

Windows PowerShell はオブジェクト指向の世界に存在しているかもしれません。ですが、さいわい、Windows PowerShell チームは、現実世界では書式設定された文字列の形式で外部データが存在することが多いと気付いたので、Select-String コマンドを盛り込みました。Select-String を使用できるようになり、また、正規表現をよく知っておけば、Windows PowerShell を使用して、どんなに複雑な文字列でも解析できる 1 行のコマンドを記述することができます。

Don Jones は『Windows PowerShell: TFM』の共著者であり、他にも IT に関連する多数の書籍を執筆しています。Don に対するお問い合わせについては、彼のブログ (www.concentratedtech.com) を参照してください。