
TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。
詳細情報
| • | |
| • | |
| • |
![]()
Scripting Guy さん、よろしくお願いします。コンマで区切られた個々のフィールドで構成されているテキスト ファイルがあります。各行の 2 番目のフィールドを確認し、そのフィールドに Everyone という単語が含まれている場合は、その行の 6 番目のフィールドの値を取得して、その値を別のテキスト ファイルに書き込む必要があります。どうすればいいでしょうか。
-- RP

RP さん、こんにちは。おそらく、多くの方が「うーん、シアトル地域での生活というのは、実際のところ、どんなものなんだろう」と思っていらっしゃるでしょう。私たちがお教えします。今朝、このコラムを執筆している Scripting Guy が車で職場に向かっていると、サイレンが聞こえてきました。救急車と消防車が猛スピードで視界に入ってくると、大半の人と同様、彼は即座に車を路肩に寄せました。2 台が近づいてきたとき、赤信号で停車していた女性が突然、思い切り車の速度を上げ、猛スピードで交差点を横切りました。そのため、救急車は急ブレーキをかけて停止しなければなりませんでした。危うく大惨事になるところでしたが、さいわい、救急車と消防車は走行を続けることができました。
では、シアトルという土地柄を考慮してお答えください。この女性は、赤信号を突っ切るだけでなく救急車や消防車と衝突しそうになるほど急いで、どこに向かっていたと思いますか。まったくそのとおりです。赤信号を突っ切り、救急車と衝突しそうになった後、この女性はスターバックスのドライブスルーに入りました。
しかし、シアトルでスターバックスが見つかる確率を考えると、彼女を責めることはできません。Scripting Guys から皆さんにちょっとしたアドバイスがあります。それは、「スターバックスを見つけたときは、すぐに立ち寄ることをお勧めします。次のスターバックスが見つかるまでに 3 〜 4 ブロックは走らなければなりませんから」ということです。
地理に関する注 : Scripting House から 8 ブロックの範囲内には、スターバックスが 2 軒、独立系のコーヒー ショップが 1 軒、食料品店の外にあるコーヒー カートが 1 つ、および駐車場に建てられた小さなドライブスルーのコーヒー小屋が 2 軒あります。それから、マクドナルドが 1 軒あります (マクドナルドでは、レギュラー コーヒーはもちろん、カフェ ラテとアイス コーヒーも販売されています)。 セブン-イレブンがあるのは言うまでもありません (セブン-イレブンでもコーヒーを販売しています)。 |
ちなみに、緊急事態の内容や救急車の行き先はわかりませんが、かなり急を要していたに違いないと思います。そうでなければ、おそらく、救急車もスターバックスに寄っていたでしょうから。
もちろん、皆さんが普通の感覚を持った方なら、おそらく、シアトル住民のコーヒーへの執着については聞き飽きているでしょう。言うまでもありませんが、普通の人なら、コンマ区切りファイルを解析し、そのファイル内の選択した行から情報を抽出し、抽出した情報を新しいファイルに保存するという作業を行うことができるスクリプトについて聞く方がはるかに良いと感じるでしょう。皆さんは幸運ですよ。女性が赤信号を突っ切ってスターバックスに寄ったとき、このコラムを執筆している Scripting Guy は、どさくさに紛れて地元のスクリプト ショップのドライブスルーに寄りました。そしてなんと、彼がそこで見つけたものは何だと思いますか。コンマ区切りファイルを解析し、そのファイル内の選択した行から情報を抽出し、抽出した情報を新しいファイルに保存するという作業を行うことができるスクリプトです。
注 : ええ、そのようなスクリプトを見つけることができるなんて、彼は本当に幸運でした。いつもは、こういうものはすぐに売り切れてしまうのです。 |
スクリプトは次のとおりです。
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
arrFields = Split(strLine, ",")
If InStr(arrFields(1), "Everyone") Then
strContents = strContents & arrFields(5) & vbCrlf
End If
Loop
objFile.Close
Set objFile = objFSO.CreateTextFile("C:\Scripts\Everyone.txt")
objFile.Write strContents
objFile.Close
スクリプトのしくみについての説明を始める前に、当該のテキスト ファイル (C:\Scripts\Test.txt) の内容を見てみましょう。
MBPGPS1PRN-001\,Administrators,LOCALGROUP,S-1-5-32-544,PRINTSHARE,\\MBPGPS1PRN-001\mbbetsb01,OWNER,, MBPGPS1PRN-001,Everyone,GLOBALGROUP,S-1-1-0,PRINTSHARE,\\MBPGPS1PRN-001\mbbetsb01,(+PrR),, MBPGPS1PRN-001,Everyone,GLOBALGROUP,S-1-1-0,PRINTSHARE,\\MBPGPS1PRN-002\mbbetsb01,(+PrR),, MBPGPS1PRN-001,Administrators,GLOBALGROUP,S-1-1-0,PRINTSHARE,\\MBPGPS1PRN-001\mbbetsb01,(+PrR),, MBPGPS2PRN-001,Everyone,GLOBALGROUP,S-1-1-0,PRINTSHARE,\\MBPGPS2PRN-001\mbbet02,(+PrR),,
RP さんのメールに書いてあったとおり、このファイルの各行は、いくつかの異なるフィールドで構成されています。各行の 2 番目の項目 (Administrators など) を確認し、Everyone いう単語が含まれているかどうかを判断する必要があります (少なくとも 1 行目では含まれていませんね)。2 番目の項目に Everyone いう単語が含まれている場合は (ファイルの 2 行目はこれに該当します)、6 番目のパラメータ (\\MBPGPS1PRN-001\mbbetsb01 などのプリンタ パス) を抽出し、その情報を別のテキスト ファイルに書き込む必要があります。
おわかりでしょうか。それは良かったです。では、スクリプトとスクリプトで使用される魔法のしくみについて説明します。
ご覧のとおり、まず、ForReading という名前の定数を定義して値 1 を代入します。この定数は、Test.txt ファイルを開くときに使用します。偶然にも、次に、Scripting.FileSystemObject のインスタンスを作成してから OpenTextFile メソッドを使用して Test.txt を読み取り用に開くという処理を行います。これを行うのが次の 2 行のコードです。
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)
ファイルを 1 行ずつ読み取って処理するには、まず、ファイルの AtEndOfStream プロパティが True になるまで実行する Do Until ループを設定する必要があります (これは「ファイルの末尾に達するまで読み取りを続ける」ということを気取った言い方で表現しているだけです)。ループ内の最初の処理では、ReadLine メソッドを使用してファイルの最初の行を読み取り、その値を strLine という名前の変数に格納します。
strLine = objFile.ReadLine
では、次の行に移りましょう。
arrFields = Split(strLine, ",")
ここでは、Split 関数を使用して strLine 変数に格納されている文字列値を配列に変換しています。もう少し詳しく説明すると、Split 関数に対して、コンマが見つかるたびに配列 arrFields の新しい要素を作成するよう、指示しています。この処理を行うのは、この処理によって、次の要素を持つ配列が作成されるからです。
| • | MBPGPS1PRN-001\ |
| • | Administrators |
| • | LOCALGROUP |
| • | S-1-5-32-544 |
| • | PRINTSHARE |
| • | \\MBPGPS1PRN-001\mbbetsb01 |
| • | OWNER |
この配列は作成する価値があるでしょうか。もちろんあります。この配列の各要素は、テキスト行の個々のフィールドと非常に見事に対応しているからです。既に述べたように、このテキスト行の 2 番目のフィールドに Everyone いう単語が含まれているかどうかを知る必要があります。これは、次に示すような非常に簡単な方法で確認できます。
If InStr(arrFields(1), "Everyone") Then
ここでは、InStr 関数を使用して、Everyone という単語がテキスト行の 2 番目のフィールドに含まれているかどうかを判断しています。もっと正確に言うと、Everyone が配列の 2 番目の要素に含まれているかどうかを確認しています。なお、使用している構文は arrFields(1) ですが、本当に配列の 2 番目の要素を確認していますので、ご心配なく。VBScript では、配列のインデックスは 0 から始まります。これはつまり、配列の最初の要素にはインデックス番号 0 が割り当てられ、2 番目の要素 (私たちが注目している要素) にはインデックス番号 1 が割り当てられるということです。arrFields(1) のようにインデックスの値が 1 であるのは、このような理由によります。配列の 3 番目の要素を確認する必要がある場合は、arrFields(2) という構文を使用します。
それ以降の要素についても、同様とお考えください。
目的の単語が arrFields(1) に含まれていない場合は、ループ処理の先頭に戻り、テキスト ファイルの次の行についても同じ処理を繰り返します。目的の単語が含まれている場合は、次のコード行を実行します。
strContents = strContents & arrFields(5) & vbCrlf
ここでは、strContents という名前の変数に値を代入しているだけです。代入しているのは、変数の既存の値に配列の 6 番目の要素の値を加え、さらに復帰改行文字 (vbCrLf) を加えた値です。ええ、インデックス番号に 5 を指定したことには、もっともな理由があります。配列の 6 番目の要素のインデックス番号は常に 5 になるというのがその理由です。
テキスト ファイルの各行を読み取って処理したら、Close メソッドを呼び出して Test.txt ファイルを閉じます。続いて、次のコード行を使用して C:\Scripts\Everyone.txt という名前の新しいテキスト ファイルを作成します。
Set objFile = objFSO.CreateTextFile("C:\Scripts\Everyone.txt")
ご想像のとおり、Test.txt から抽出したデータの書き込みはここで行う予定です。この処理は、次のように、Write メソッドを呼び出し、strContents 変数を渡すことにより行います。
objFile.Write strContents
その後、Everyone.txt ファイルを閉じて、その中身を確認すると、内容は次のようになっています。
\\MBPGPS1PRN-001\mbbetsb01 \\MBPGPS1PRN-002\mbbetsb01 \\MBPGPS2PRN-001\mbbet02
つまり、このファイルに記載されているのは Everyone グループがアクセスできるプリンタです (Test.txt ファイルが、各グループがアクセスできるプリンタについて記述されているものだとすれば、という但し書き付きですが)。
RP さん、これでうまくいくでしょう。少なくとも、私たちはうまくいくと願っています。というのも、私たちは、もうしばらくここにとどまってテキスト ファイルの解析について語りたいところですが、もう行かなくてはならないからです。コーヒー休憩の時間ですからね。
注 : 実際のところ、シアトルの人はコーヒー休憩をとりません。つまり、私たちシアトル住民は、コーヒーを少し飲むために数分間、仕事の手を休めるということはありません。その代わりに、私たちは "仕事休憩" をとります。つまり、仕事を少しするために数分間、コーヒーを飲む手を休めるのです。 |