PowerShell による GUI の自動化
どうも,筆者です.
今回は,Windows に搭載されている PowerShell を利用したスクリプトについて説明する.
経緯
あるソフトウェアで,データを呼び出し,スクショを撮って画像として保存する必要があった.2~3 枚なら手でやろうと思うけれども,200 枚,300 枚もあると流石に自動化したくなる.また,ソフトウェアは,Windows 版の GUI のものしかない.そのため,Windows の GUI を自動化する方法を探すこととなった.
UI Automation
調べたところ,Windows の PowerShell に,「UI Automation」を導入することで GUI の自動化ができるらしい.
早速,http://uiautomation.codeplex.com/ からダウンロードしてきた.保存場所は,「C:\winPowerShell\UIAutomation」というディレクトリを作成し,その中に展開した. そのままでは,PowerShell のスクリプトを書いても実行できないらしい.そのため,管理者権限で「Windows PowerShell ISE」を起動させ,以下のコマンドで実行権限を変える.
Set-ExecutionPolicy RemoteSigned
ちなみに,はてなブログでは,ps1 でコードが PowerShell と認識されるらしい.便利になったものだ.
やりたいこと
さて,実際にコードを書いていくことになる.しかし,普段 GUI で行っている操作をいきなりスクリプトに落とそうとしても無理がある.そのため,色々調べて回った. 調べたところ,先程ダウンロードした UI Automation には,UIAutomationSpy.exe というスクリプトを書く際の補助ツールなるものがあるらしい. このツールを借りて,作業を行う.ここでは,以下のような流れで処理を行う.
- データがあるディレクトリまでの絶対パスと参照するデータ名を設定する.
- 起動させたいソフトウェアを絶対パスで指定し,起動する.
- ソフトウェアから,上記で示したデータを参照し,開く.
- Alt + PrintScreen により,画面をクリップボードに保存する.
- mspaint を実行し,ペイントを起動し,Ctrl + V でクリップボードの画像を貼り付ける.
- Ctrl + S で保存する.この時,新規保存となるので,保存先のパスと保存するファイル名を指定する.
- これをデータの数だけ繰り返す.
スクリプトを書く
実際に調べながらコードを書いてみた.ます,最初に記述すべき項目として,以下のものがある.
Import-Module C:\winPowerShell\UIAutomation\UIAutomation.dll
これは,UI Automation を利用することを PowerShell 側に知らせるコードである.後は自由に書くだけだが,筆者のように何も知らない人は調べるところから始まる.今回は,キー操作がメインとなるので,キーの一覧を探した.使いそうなものを以下に示しておく.
<# Left mouse button LBUTTON = 0x01, Right mouse button RBUTTON = 0x02, Control-break processing CANCEL = 0x03, BACKSPACE key BACK = 0x08, TAB key TAB = 0x09, CLEAR key CLEAR = 0x0C, ENTER key RETURN = 0x0D, SHIFT key SHIFT = 0x10, CTRL key CONTROL = 0x11, ALT key MENU = 0x12, PAUSE key PAUSE = 0x13, CAPS LOCK key CAPITAL = 0x14, ESC key ESCAPE = 0x1B, SPACEBAR SPACE = 0x20, PAGE UP key PRIOR = 0x21, PAGE DOWN key NEXT = 0x22, END key END = 0x23, HOME key HOME = 0x24, LEFT ARROW key LEFT = 0x25, UP ARROW key UP = 0x26, RIGHT ARROW key RIGHT = 0x27, DOWN ARROW key DOWN = 0x28, SELECT key SELECT = 0x29, PRINT key PRINT = 0x2A, EXECUTE key EXECUTE = 0x2B, PRINT SCREEN key SNAPSHOT = 0x2C, INS key INSERT = 0x2D, DEL key DELETE = 0x2E, HELP key HELP = 0x2F, 0 key VK_0 = 0x30, 1 key VK_1 = 0x31, 2 key VK_2 = 0x32, 3 key VK_3 = 0x33, 4 key VK_4 = 0x34, 5 key VK_5 = 0x35, 6 key VK_6 = 0x36, 7 key VK_7 = 0x37, 8 key VK_8 = 0x38, 9 key VK_9 = 0x39, A key VK_A = 0x41, B key VK_B = 0x42, C key VK_C = 0x43, D key VK_D = 0x44, E key VK_E = 0x45, F key VK_F = 0x46, G key VK_G = 0x47, H key VK_H = 0x48, I key VK_I = 0x49, J key VK_J = 0x4A, K key VK_K = 0x4B, L key VK_L = 0x4C, M key VK_M = 0x4D, N key VK_N = 0x4E, O key VK_O = 0x4F, P key VK_P = 0x50, Q key VK_Q = 0x51, R key VK_R = 0x52, S key VK_S = 0x53, T key VK_T = 0x54, U key VK_U = 0x55, V key VK_V = 0x56, W key VK_W = 0x57, X key VK_X = 0x58, Y key VK_Y = 0x59, Z key VK_Z = 0x5A, Left Windows key LWIN = 0x5B, Right Windows key RWIN = 0x5C, Applications key APPS = 0x5D, Numeric keypad 0 key NUMPAD0 = 0x60, Numeric keypad 1 key NUMPAD1 = 0x61, Numeric keypad 2 key NUMPAD2 = 0x62, Numeric keypad 3 key NUMPAD3 = 0x63, Numeric keypad 4 key NUMPAD4 = 0x64, Numeric keypad 5 key NUMPAD5 = 0x65, Numeric keypad 6 key NUMPAD6 = 0x66, Numeric keypad 7 key NUMPAD7 = 0x67, Numeric keypad 8 key NUMPAD8 = 0x68, Numeric keypad 9 key NUMPAD9 = 0x69, Multiply key MULTIPLY = 0x6A, Add key ADD = 0x6B, Separator key SEPARATOR = 0x6C, Subtract key SUBTRACT = 0x6D, Decimal key DECIMAL = 0x6E, Divide key DIVIDE = 0x6F, F1 key F1 = 0x70, F2 key F2 = 0x71, F3 key F3 = 0x72, F4 key F4 = 0x73, F5 key F5 = 0x74, F6 key F6 = 0x75, F7 key F7 = 0x76, F8 key F8 = 0x77, F9 key F9 = 0x78, F10 key F10 = 0x79, F11 key F11 = 0x7A, F12 key F12 = 0x7B, NUM LOCK key NUMLOCK = 0x90, SCROLL LOCK key SCROLL = 0x91, #>
これは,実際に実装されているものらしい.これを利用しつつコードを書く.
パラメータの設定
まずは,パラメータの設定からはじめる.ここでは,ファイル名の末尾に連番の数字を振ってデータを識別する.
# データファイルがあるディレクトリパス $dataPath = "C:\Users\...\dataDir" # 画像を保存するディレクトリパス $savePath = "C:\Users\...\imgDir" # 起動するソフトウェア $exePath = "C:\Users\...\hoge.exe"; # ファイル名の開始と終了 $startFileNum = 1; $endFileNum = 500;
ソフトウェアの起動
次に,ソフトウェアを起動するコードを書く.ここでは,最大化して表示する.
######################################################## # 指定したパスにあるプログラムを起動し、最大化して表示 # ######################################################## $process = Start-Process $exePath -PassThru -windowstyle Maximized | Get-UiaWindow;
この「Start-Process」でプロセスを起動する.Get-UiaWindow は,起動したソフトウェアをアクティブにするものだという認識だ(細かいことは知らない).
対象とするデータを開く
そして,ソフトウェアから対象とするデータを開く.ここでは,「hoge001.dat」,「hoge002.dat」という風に名前がついているものとする.連番を $idx で指定する.また,「Alt → r → u」で読み込み画面が開くものとする(通常のソフトは Ctrl + O のはず,これが特殊なだけ).
# 対象のファイルを設定 $idx = 2; # 番号 $padNum = $idx.ToString("000"); # 0 詰め 3 桁の数値とする(2 なら 002, 10 なら 010) $targetFile = "hogehoge" + $padNum + ".dat"; # 開くファイル $imgFile = "foo" + $padNum + ".png"; # 保存するファイル # ここでは,Alt を押した後,r → u の順でキーを押すと,開く画面が出る $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; # Alt キーを押す $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_R) | Out-Null; # r キーを押す $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_U) | Out-Null; # u キーを押す
おなじみの「開く」という画面が出る.ここでは,$dataPath で指定したパスを入力し,対象とするファイルを開く. まず,「開く」という画面をアクティブにする.ここで,「UIAutomationSpy.exe」を使用した.アクティブにするには,
$openWnd = Get-UiaWindow -Name '開く';
とすればよいらしい.代入する変数名は何でもよい.次に,パスを設定する.パスは,F4 キーを押して入力モードにし,Ctrl + A で全選択,Delete キーで削除,その後,$dataPath で指定したパスを書き込み,Enter を押すという流れになる.これを,コードで書くと以下のようになる.
$openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::F4) | Out-Null; # F4 キーを押す $openWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; # Ctrl キーを押し続ける(KeyDown に注目) $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_A) | Out-Null; # A キーを押す(全選択状態となる) $openWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; # Ctrl キーを離す(KeyUp) $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::DELETE) | Out-Null; # Delete キーを押す(削除) $openWnd.Keyboard.TypeText($dataPath) | Out-Null; # テキストを書き込む $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; # Enter を押す(RETURN として定義)
最後に,$targetFile で指定したファイル名を「ファイル名(N):」の欄に記入する必要がある.これが面倒であった.UIAutomationSpy.exe には,available patterns という項目があり,ここに,「ValuePattern」や「TextPattern」など,設定するための項目が記されている.今回は, http://uiautomation.codeplex.com/wikipage?title=Object%20model&referringTitle=Documentation で使い方を調べた.英語だが,何とかなる.その結果,以下のようなコードが書ける.
# リスト中にあるアイテムを選択して開く $selectItem = $openWnd | Get-UiaEdit -Name 'ファイル名(N):'; $selectItem.Value = $targetFile; $selectItem.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; # 0.5 秒停止 Start-Sleep -m 500
画面をクリップボードに保存
開いたデータの画面を PrintScreen でクリップボードにコピーする.
# 表示された データファイルを画像として保存 $process.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; # Alt キーを押す $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::SNAPSHOT) | Out-Null; # PrintScreen キーを押す $process.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; # Alt キーを離す
ペイントに貼り付け
ペイントは「mspaint」で起動できるので,絶対パスの指定はいらない.
# ペイントを起動 $paintWnd = Start-Process mspaint -PassThru -windowstyle Maximized | Get-UiaWindow; # クリップボードにある画像を貼り付ける $paintWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_V) | Out-Null; $paintWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null;
名前を付けて保存
# 保存 $paintWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_S) | Out-Null; $paintWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $openWnd = Get-UiaWindow -Name '名前を付けて保存'; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::F4) | Out-Null; $openWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_A) | Out-Null; $openWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::DELETE) | Out-Null; $openWnd.Keyboard.TypeText($savePath) | Out-Null; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; $saveProcess = $openWnd | Get-UiaEdit -Name 'ファイル名:' $saveProcess.Value = $imgFile; $saveProcess.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; # ペイントを閉じる $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_F) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_X) | Out-Null; # 0.5 秒停止 Start-Sleep -m 500
スクリプト全体
以上のスクリプトを for 文を用いてループ処理にかければよい.
Import-Module C:\winPowerShell\UIAutomation\UIAutomation.dll # データファイルがあるディレクトリパス $dataPath = "C:\Users\...\dataDir" # 画像を保存するディレクトリパス $savePath = "C:\Users\...\imgDir" # 起動するソフトウェア $exePath = "C:\Users\...\hoge.exe"; # ファイル名の開始と終了 $startFileNum = 1; $endFileNum = 500; ######################################################## # 指定したパスにあるプログラムを起動し、最大化して表示 # ######################################################## $process = Start-Process $exePath -PassThru -windowstyle Maximized | Get-UiaWindow; # 対象のファイルを設定 for ($idx = $startFileNum ; $idx -le $endFileNum ; $idx++) { $padNum = $idx.ToString("000"); # 0 詰め 3 桁の数値とする(2 なら 002, 10 なら 010) $targetFile = "hogehoge" + $padNum + ".dat"; # 開くファイル $imgFile = "foo" + $padNum + ".png"; # 保存するファイル # ここでは,Alt を押した後,r → u の順でキーを押すと,開く画面が出る $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; # Alt キーを押す $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_R) | Out-Null; # r キーを押す $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_U) | Out-Null; # u キーを押す $openWnd = Get-UiaWindow -Name '開く'; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::F4) | Out-Null; # F4 キーを押す $openWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; # Ctrl キーを押し続ける(KeyDown に注目) $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_A) | Out-Null; # A キーを押す(全選択状態となる) $openWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; # Ctrl キーを離す(KeyUp) $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::DELETE) | Out-Null; # Delete キーを押す(削除) $openWnd.Keyboard.TypeText($dataPath) | Out-Null; # テキストを書き込む $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; # Enter を押す(RETURN として定義) # リスト中にあるアイテムを選択して開く $selectItem = $openWnd | Get-UiaEdit -Name 'ファイル名(N):'; $selectItem.Value = $targetFile; $selectItem.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; # 0.5 秒停止 Start-Sleep -m 500 # 表示された データファイルを画像として保存 $process.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; # Alt キーを押す $process.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::SNAPSHOT) | Out-Null; # PrintScreen キーを押す $process.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; # Alt キーを離す # ペイントを起動 $paintWnd = Start-Process mspaint -PassThru -windowstyle Maximized | Get-UiaWindow; # クリップボードにある画像を貼り付ける $paintWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_V) | Out-Null; $paintWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; # 保存 $paintWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_S) | Out-Null; $paintWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $openWnd = Get-UiaWindow -Name '名前を付けて保存'; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::F4) | Out-Null; $openWnd.Keyboard.KeyDown([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_A) | Out-Null; $openWnd.Keyboard.KeyUp([WindowsInput.Native.VirtualKeyCode]::CONTROL) | Out-Null; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::DELETE) | Out-Null; $openWnd.Keyboard.TypeText($savePath) | Out-Null; $openWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; $saveProcess = $openWnd | Get-UiaEdit -Name 'ファイル名:' $saveProcess.Value = $imgFile; $saveProcess.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null; # ペイントを閉じる $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::MENU) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_F) | Out-Null; $paintWnd.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::VK_X) | Out-Null; # 0.5 秒停止 Start-Sleep -m 500 }
これで,スクリプトが完成した.これを,guiAuto.sp1 とでも命名し,適当なディレクトリに保存する.その後,Windows PowerShell ISE を起動し,「(ファイルがあるパス)\guiAuto.sp1」とするとスクリプトが走る.
今後
今回は,調べつつただ書いただけのものができた.関数も使えるらしいので,次やるときは,関数を利用して,機能ごとに分けたものを作成したい.