PowerShell でファイル比較 (解説・補足)

2013 年最後の投稿としては少々残念な内容になりますが・・・

2013年12月24日の記事に書いたスクリプトには、一つ問題があります。

「kijun.txt」・「hikakutaishou.txt」の、いずれかないし両方のテキストファイルの中身が一行だけだった場合、後半の「各行比較」工程において意図しない動作をしてしまうのです。

 

 

この問題を引き起こすのは、 " (Get-Content テキストファイル名)[行] " の部分です。

解説・後半 2/2 に書いた通り、この部分はテキストファイルの [$LN] 行目の文字列を抜き出すことが目的です。

しかし、一行しか無いテキストファイルに対してこれを行うと、[$LN] 文字目の一文字だけを抜き出してしまうのです。

これでは、両テキストファイルの内容が一致しているか否かを、正確に判定出来ません。

 

 

一行だけのテキストファイルに対し、その一行の文字列(つまりそのテキストファイル全体)を抜き出す場合は、対象行を指定する " [ ] " が不要となります。

適宜スクリプトを書き換えてご利用ください。

if 構文を使って、「$NoK」と「$NoH」のいずれかないし両方が「 1 」だった場合の条件分岐を行えばよいのですが、複雑になりそうなので止めておきます。

 

 

なお、このスクリプトが「PowerShell 2.0 以降」でしか動かないのは、配列演算子 " -join " が PowerShell 1.0 には無いためです。

" -join " を使わない形に書き換えれば、Windows Vista Enterprise ( Service Pack 2 ) の PowerShell 1.0 でも実行可能であることを確認済みです。

 

 

それでは私は年越し蕎麦を食べに行ってきます。

皆様も良いお年をお迎えください。

 

PowerShell でファイル比較 (解説・後半 2/2)

最後に、判定処理について解説します。

 

 

最初に、「 $K 」,「 $H 」という2つの変数を定義しています。

どちらも、その中身には " (Get-Content テキストファイル名)[行] " を格納しているのですが、これは一度テキストファイルの全文を読み込んでから、指定の行の文字列を抜き出すというものです。

これにより、基準となる「kijun.txt の $LN 行目」と、比較対象となる「hikakutaishou.txt の $LN 行目」の文字列を抜き出すことができます。

 

 

次はそれらが一致しているか否かを判定するのですが、判定自体は、前半でも使った比較演算子 " -eq " を使えば簡単です。

両文字列が完全に同じものであれば「True」、少しでも違えば「False」という実行結果になります。

 

 

各行の実行結果を、そのまんま一行ずつ「kekka.txt」に出力しても良いのですが、何行目が「True」で何行目が「False」なのかが分かりやすいよう、一工夫します。

実行結果がどちらであれ、まずそれを「 $C 」という変数に格納します。

次に、判定対象行を示す変数「 $LN 」に、+1 し、新たな変数「 $LN2 」に格納します。

※ +1 するのは、PowerShell 上で「ゼロ」から始まる行数を、人間にも分かりやすい「1」から始まる行数に直すためです。

最後に、$LN2 と $C を連結して一続きの文字列にします。

こうすれば、何行目が「True (あるいは False ) 」なのかが分かりやすく出力されます。

 

 

しかし、連結には注意が必要です。前半でやったように、単純に「+」で並べる事は出来ません。

それをしてしまうと、「True = 1」、「False = 0」と見做して足し算が行われてしまいます。

 

 

このような場合は、" -join " という配列演算子を用いて連結ます。

先に「 $R 」という変数を定義し、 $LN2 と $C を「カンマ区切り」で格納します。

これだけだと、$R の中身は「改行された二行のテキスト」になってしまうのですが、次に $R -join " : " を実行することで「コロンによって連結された一行のテキスト」に変換できます。

それを「kekka.txt」に出力することで、「何行目が一致していて、何行目が不一致なのか」が分かるようになります。

 

 

以上で、2013年12月24日の記事に書いたスクリプトの解説は終了です。

が、しかし・・・・

ちょっと書き足りないことがあるので補足編に続きます。

PowerShell でファイル比較 (解説・後半 1/2)

引き続き、スクリプト後半の「各行比較」、つまり両テキストファイルの中身を一行ずつ突き合わせて一致 or 不一致を判定する工程について解説します。

 

 

後半のスクリプトは、全体が While 構文によって構成されています。

While 構文は何らかの処理を繰り返し実行させたい場合に便利で、CSV 形式で記述された一覧表を元にドメインユーザーを作成する際にも利用しました。

 

 

まずは全体の流れから説明します。

PowerShell において先頭の行は「ゼロ」行目として扱われるため、一致/不一致を判定する処理も、最初は「ゼロ」行目を対象にしてスタートします。

そしてその行についての確認が完了したら、次はその「+1」行目に対して同じ処理を行います。

その繰り返しを、基準となるテキストファイル「kijun.txt」の最後の行まで繰り返します。

 

 

こういった処理を、While 構文で記述すると以下のようになります。

まず最初の " $LN = 0 " により、処理対象の行を示す「変数 $LN 」に、数値「ゼロ」を格納します。

お次は条件定義です。" while ($LN -le $NoK-1) " は、行の値が「 $NoK-1 」以下であれば処理を続行し、超えたら終了することを意味します。

変数 $NoK 自体は、基準となる「kijun.txt」の全行数を示す変数として前半で定義済みですが、一行目が「ゼロ」としてスタートするため、最終行は「全行数 -1」となります。

-1 が無いと、一回余計に処理が行われてしまうので注意が必要です。

※ 比較演算子として " -le " (以下) ではなく " -lt " (未満) を用い、 " while ($LN -lt $NoK) " と記述しても同じことです。

この条件定義に続く、{ } で括られた部分に、実際に繰り返したい処理が記述されています。

その最後にある " $LN++ " は、変数 $LN に格納された数値に +1 するための記述です。

これにより、次回は「次の行」に対して同様の処理が行われる事となります。

" $LN++ " より前の部分こそが、このスクリプトのキモとなる「判定処理」なのですが、この部分についてはまた次回詳述します。

 

 

後半 2/2 へ続く。

PowerShell でファイル比較 (解説・前半)

前回ご紹介したスクリプトは前半の「総行数比較」と後半の「各行比較」に分かれており、今回は前半を解説します。

 

 

まず、「$NoK」と「$NoH」という二つの変数を定義しています。

これらが各テキストファイルの行数を表すのですが、そのためにコマンドレットを二つ使っています。

Get-Content コマンドレットでテキストファイルの全文を読み込み、それをパイプで  Mesure-Object コマンドレットに渡す仕組みです。

Mesure-Object というのは統計情報を算出してくれるコマンドレットで、実行結果の「Count」というプロパティにはテキストの行数が出ます。

(その他、得点表のような CSV ファイルを読み込ませて、平均値を出すことなどが可能です。)

 

 

Get-Content から始まるコマンドレットの全体を「 ( ) 」で括り、最後に 「.Count」 を付ける事により、実行結果から「Count」というプロパティだけを得ることが出来ます。

その結果として、「$NoK」には「5」、「$NoH」には「4」という値が格納されます。

 

 

この二つの変数が一致するか否かを、比較演算子「-eq」により判定します。

今回のケースでは一致しないので実行結果は「False」となりますが、一致すれば「True」となります。

 

 

最後に各テキストファイルの行数を出力するのですが、値だけが出力されても分かりにくいので、「基準」「比較対象」といったタイトルと、「行」という単位を付加します。

文字列を連結する場合は、「 " " 」で括って「 + 」で繋げます。

なお、文字列と数値を連結する場合、数値の方は「 " " 」で括らなくてもいいようです。

(ただし、数値と数値を「 + 」で繋げた場合は、足し算が行われるので注意が必要です。)

 

 

後半へ続く。

PowerShell でファイル比較

今回のテーマは「2 つのテキストファイルの中身を比較し、一致するかどうか確認する」というものです。

PowerShell にはそのような用途のための Compare-Object というコマンドレットもあるのですが、実行結果の表記にクセがあり、私の求めるものではなかったので自分でスクリプトを書きました。

2 つのテキストファイルに対し、一行目から順番に「文字列が完全一致するか否か」を確認し、各行毎に「True ( 一致する )」ないし「False ( 一致しない )」という結果を出力するスクリプトです。

 

 

まず、E ドライブ直下に基準となる「kijun.txt」と、比較対象となる「hikakutaishou.txt」の 2 つのテキストファイルを作成します。

それぞれの中身は下記の通り。

------ E:¥kijun.txt ココカラ ------------------

aaaaa

bbbbb

ccccc

 

eeeee

------ ココマデ (全 5 行) -----------------------

------ E:¥hikakutaishou.txt ココカラ -------

aaaaa1

bbbbb

ccc

ddddd

------ ココマデ (全 4 行) -----------------------

 

 

2 つのテキストファイルは総行数からして違いますし、文字列が一致している行は 2 行目だけです。

そのことを実行結果 ( kekka.txt ) として得るためのスクリプトは以下の通りです。(PowerShell 2.0 以降で利用可能です。)

=== スクリプト ココカラ ==============================

"【総行数比較】" > e:¥kekka.txt

$NoK = (Get-Content e:¥kijun.txt | measure-object).count

$NoH = (Get-Content e:¥hikakutaishou.txt | measure-object).count

$NoK -eq $NoH >> e:¥kekka.txt

"基    準 : " + $NoK + " 行" >> e:¥kekka.txt

"比較対象 : " + $NoH + " 行" >> e:¥kekka.txt

"+++++++++++++++++" >> e:¥kekka.txt

"【各行比較】" >> e:¥kekka.txt

$LN = 0

while ($LN -le $NoK-1)

{

$K = (Get-Content e:¥kijun.txt)[$LN]

$H = (Get-Content e:¥hikakutaishou.txt)[$LN]

$C = $K -eq $H

$LN2 = $LN+1

$R = $LN2,$C

$R -join " : " >> e:¥kekka.txt

$LN++

}

=== スクリプト ココマデ ==============================

 

 

内容の解説は次回をお待ちください。

Virtual Bytes と PowerShell

Virtual Bytes」とは、パフォーマンスモニタでログを取ることのできるカウンターの一種で、プロセスが使用している仮想アドレス領域の現在の大きさを、バイト数で表します。

(パフォーマンスモニタの詳細な使い方や、「そもそも 仮想アドレス領域 とは何か」という説明は割愛します。)

 

 

今回の主題は、パフォーマンスモニタではなく PowerShell の「Get-Process」コマンドレットを用いて Virtual Bytes の値を確認する際の注意点です。

 

 

コマンドレット例をできるだけシンプルに書くと、こんな感じです。

Get-Process  -name (プロセス名) |  Format-List VirtualMemorySize

※ PowerShell 1.0 でも実行可能です。

※ svchost.exe のように同名で複数存在するプロセスのうち一つだけを指定する場合は、-name ではなく -id によりプロセス固有の「プロセス ID」を指定する必要があります。

 

 

ところが、これでは 64 bit 版の OS に通用しない事があるのです。

値が小さいうちはいいのですが、だいたい 2 GB を超えたぐらいから、なぜかマイナスの値が出てきてしまいます。

(32 bit 版 の OS においては、仮想アドレス領域の上限はデフォルトで「2GB」ですから、そのせいではないかと推測しています。)

 

 

こんな時には、切り出すプロパティを変更します。

Get-Process  -name (プロセス名) |  Format-List VirtualMemorySize64

を実行することで、パフォーマンスモニタ側の「Virtual Bytes」と同じ値を確認出来ます。

名前からして、この「VirtualMemorySize64」こそが 64 bit 環境において確認すべき正しいプロパティなのでしょう。

 

 

 

なお、仮想メモリ領域が徐々に食い潰されていく(パフォーマンスモニタ上で「Virtual Bytes」の値が右肩上がりに上昇していく)様子を確認するには、下記の不具合を利用するという手が有ります。

The handle count and "Virtual Bytes" for the Windows Event Log service keep increasing in Windows Server 2008 or in Windows Vista when you refresh scheduled task history events

 

 

2013 年 12 月 22 日 現在、まだ日本語版のページが作られていません・・・

が、この現象を発生させるのは簡単です。

タスクスケジューラー上で何らかのタスクの「履歴」タブを開き、[最新の情報に更新] ボタンを連打するだけです。

 

 

なお、この不具合は Windows Vista および Windows Server 2008 で発生するものとされ、修正プログラムも出ているのですが、私は Windows 7 でも同様の現象が起きる事を確認しています。

Windows 7  向けの修正プログラムはいつ出るのでしょう・・・

 

Windows の NTP サーバー

人間は、電話番号「117」で時報を聞き、時計の時刻を修正します。

コンピューターの時刻も次第にズレますから、信頼する NTP サーバーに適宜問い合わせ、自身の時刻を修正します。

 

 

Windows も、NTP サーバーとしての機能を持っています。ただしデフォルトでは無効です。

グループポリシーやレジストリの設定により有効化できる他、Windows Server をドメインコントローラーとして構築した場合には、自動的にドメイン内でメンバーコンピューターから参照される NTP サーバーになります。

また、" w32tm " というコマンドにより、各種設定や状態確認が可能です。

 

 

しかし・・・ どういうわけか、GUI の設定画面が存在しません。

全く解せません。

 

決して火曜日だからというわけではないが、ふと、火について考えてみた。

 

 

人類がまだ火を使いこなせなかった太古の昔は、人類が火を目撃するとしたら、稀に落雷などで自然発生する山火事の時ぐらいだっただろう。あとは、さらに稀な噴火ぐらいだろうか。

そんな古代人にとっての火は単に「危険」なだけでなく、現代人からは想像もつかないほど「特別」かつ「不可思議」であり、それゆえに「恐(畏)れる」べき存在だったに違いない。

 

 

では、古代人はいったい何をモチベーションにして創意工夫を重ね、火をコントロールするに至ったのだろうか。

ゼロからスタートし、多くのリスクを冒しながらトライ&エラーを繰り返すことは、20世紀中盤における「月面着陸」よりも遥かに壮大かつ無謀な挑戦だったはずだ。

それなりに強い「動機付け」があったに違いない。

 

 

火を使うことで「夜でも明るい」「猛獣除けになる」「便利な土器を作れる」といった利点が有るが、それらが動機として十分なものだとはどうしても思えない。

古代人を駆り立てた直接の動機は、「うまい焼き肉が食いたい」というシンプルな欲求だったのではないかと思う。

山火事の焼け跡には、逃げ後れた野生動物の「天然の焼き肉」が転がっていただろう。古代人はそれに味をしめ、なんとか自力で焼き肉を作りたいと強く願うようになったのではないだろうか。

古今東西の人類にとって、最も普遍的かつ強力な欲求は「食欲」だと思うので。

 

 

なんてことを考えてみました。ヒマなので。

 

support.microsoft.com の日本語訳について。

Windows はいくまでもなく米国製のソフトウェアですから、多くの技術文書はオリジナルが英語で記述され、それが世界各国の言語へ翻訳されています。

しかし、多くの技術文書は翻訳ソフトにより翻訳されているため、日本語としては不自然な記述であることも珍しく有りません。

そんな時は仕方が無いのでオリジナルの英語文書を頑張って読むのですが、むしろ積極的にオリジナルを読んだ方が良い理由が、実は他にもあります。

(正直言うと私は英語が大の苦手なのですが、仕事として Windows を扱っている以上、そうも言っていられません・・・)

 

 

それは、「文書の更新」です。

一度公開された技術文書も、必要に応じて随時更新されます。

しかし、日本語訳の更新がオリジナルに追いついておらず、大事な情報が加筆されていないケースが稀に有るのです。

 

 

例えば下記のページをご覧ください。

[オリジナル]

How to harden the TCP/IP stack against denial of service attacks in Windows Server 2003

http://support.microsoft.com/kb/324270/en

[日本語訳]

Windows Server 2003 で DoS 攻撃に対して TCP/IP スタックを強化する方法

http://support.microsoft.com/kb/324270/ja

 

 

機械翻訳であるとの表記が無く、日本語としても自然なため、人力翻訳だと思われます。

手間をかけてくれるのは有り難いのですが、プロパティの項に記載された "リビジョン" を見ると、2013年12月2日現在、オリジナルが「14.0」で日本語訳が「2.0」です。

まるで追いついていない状態のまま3年近く放置されているわけですから、おそらく今後もこのままでしょう。

 

 

私も両者の内容を緻密にチェックしたわけではありませんが、大きな違いとしては「Note  (日本語訳における " 注 " ) の数」が挙げられます。

オリジナルだと3つあるのに対し、日本語訳は2つだけです。

興味の有る方は、 " オリジナルに有って、日本語訳に無い Note " を見つけて読んでみてください。

けっこう大事な事が書いてありますよ。