PowerShellで正規表現フィルタを書いてみる

Windowsにおいて標準で利用できるスクリプト環境としては古くからWindows Scripting Host(WSH)があるが、Windows 7以降ではこれに加えPowerShellと呼ばれるシェルが利用できる。 また、WSHJScriptまたはVBScriptのもとでCOMコンポーネントを扱えたように、PowerShellでは独自のシェル構文のもとで.NET Frameworkライブラリを扱うことができ、シェルでありながら汎用プログラミング環境としても使えるものになっている。 そこで、ここではPowerShellスクリプト正規表現フィルタを書き、コマンドプロンプトからスクリプトとして実行してみる。

環境

Windows 8.1 Pro 64 bit版、PowerShell 4.0

>systeminfo
OS 名:                  Microsoft Windows 8.1 Pro
OS バージョン:          6.3.9600 N/A ビルド 9600
OS ビルドの種類:        Multiprocessor Free
システムの種類:         x64-based PC
プロセッサ:             1 プロセッサインストール済みです。
                        [01]: Intel64 Family 6 Model 69 Stepping 1 GenuineIntel ~1596 Mhz

>powershell -c "$PSVERSIONTABLE"

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.34014
BuildVersion                   6.3.9600.17090
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

16進バイト列をC文字列に変換するPowerShellスクリプト

「Windowsで電卓を起動するアセンブリコードを書いてみる」では、アセンブル結果としてdumpbin /rawdataで表示されたバイト列をC文字列に変換した。 この処理をPowerShellスクリプトで書くと、次のようになる。

# getsc.ps1
-join (
    $input | 
    Select-String " ([0-9A-F]{2})(?= )" -CaseSensitive -AllMatches | 
    ForEach-Object { $_.Matches } | 
    ForEach-Object { "\x" + $_.Groups[1] }
)

このスクリプトは指定した正規表現にマッチした1番目のグループをすべて取り出し、C文字列としてエスケープした上で連結するものである。 なお、ForEach-Objectforeachあるいは%と書くこともできる。 このことはPowerShell上で次のようにして確認できる。

PS C:\> Get-Alias | Where-Object { $_.Definition -eq "ForEach-Object" }

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           % -> ForEach-Object
Alias           foreach -> ForEach-Object

上のエントリで書いたアセンブリコードから生成した実行ファイルに対しdumpbin /rawdataアセンブル結果を表示し、その結果を上のスクリプトで処理してみる。

>ml execcalc.asm /link /subsystem:console
Microsoft (R) Macro Assembler Version 12.00.31101.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: execcalc.asm
Microsoft (R) Incremental Linker Version 12.00.31101.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/OUT:execcalc.exe
execcalc.obj
/subsystem:console

>dumpbin /rawdata execcalc.exe
Microsoft (R) COFF/PE Dumper Version 12.00.31101.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file execcalc.exe

File Type: EXECUTABLE IMAGE

RAW DATA #1
  00401000: 33 C0 50 68 63 61 6C 63 8B C4 6A 01 50 B8 27 29  3ÀPhcalc.Äj.P¸')
  00401010: 80 75 FF D0 50 B8 64 7F 7E 75 FF D0              .uÿÐP¸d.~uÿÐ

  Summary

        1000 .text

>dumpbin /rawdata execcalc.exe | powershell -ex remotesigned -f getsc.ps1
\x33\xC0\x50\x68\x63\x61\x6C\x63\x8B\xC4\x6A\x01\x50\xB8\x27\x29\x80\x75\xFF\xD0\x50\xB8\x64\x7F\x7E\x75\xFF\xD0

PowerShellスクリプトの実行は、powershellコマンドに-fオプションでファイルパスを指定することにより行うことができる。 ただし、デフォルト状態では一切のスクリプト実行が制限されているため、ここでは-exオプションによりポリシーをremotesigned、すなわちローカルスクリプトについてはデジタル署名の有無によらず実行できるよう変更している。 なお、-ex-executionpolicyエイリアスであり、-epと書くこともできる。

関連リンク