Powershell UiautomationでWinmergeの比較結果をレポート出力をする

##初めに
Powershellで何とかGUI操作を自動化できないか探していたら「UI Automation PowerShell Extensions」というツールを見つけました。とりあえず実験的に作成しました。
客先常駐が多く、VisualStudio等インストールできないため、こっそり業務改善できるこういったツールはありがたいです。

※どうも配布が終了しているらしく、下記ページの再配布版をダウンロードするしかないようです。
https://www.code-lab.net/?page_id=21648
またダウンロードしたファイルを「プロパティ」→「全般タブ」→「セキュリティ」→「許可する(K)」のチェックを入れて解凍しないとインポートできないようなので注意。

##内容
更新後と更新前のフォルダに入っている複数の更新前と後のファイルを比較してHTML形式でレポートを出力します。

※WinMergeの標準の機能でフォルダ事比較はできるのですが
レポートのHTMLファイルを一つづつ生成できないのでこのツールを作りました。

```Powershell
Import-Module "C:\work\UIAutomation.0.8.7B3.NET40\UIAutomation.dll" #UIAutomation.dllがあるパスを指定する

#Version 2.12.4.3+jp-3-Japanese Unicode x86 で動作確認
#PSVersion                      5.1.14409.1012 で動作確認

$i = 0

$UIAElement       = [System.Windows.Automation.AutomationElement]
$UIAChildrenScope = [System.Windows.Automation.TreeScope]::Children
$UIASubTreeScope = [System.Windows.Automation.TreeScope]::SubTree
$UIADescendantsScope = [System.Windows.Automation.TreeScope]::Descendants
$UIATrue          = [System.Windows.Automation.Condition]::TrueCondition
$UIAInvokePattern = [System.Windows.Automation.InvokePattern]::Pattern
$UIAExpandPattern = [System.Windows.Automation.ExpandCollapsePattern]::Pattern
$UIAWindowPattern = [System.Windows.Automation.WindowPattern]::Pattern
$UIAValuePattern = [System.Windows.Automation.ValuePattern]::Pattern
$UIATextPattern = [System.Windows.Automation.TextPattern]::Pattern
[UIAutomation.Preferences]::Highlight = $true　#赤枠の非表示

#デバッグ用：WINMERGEを停止させる、出力したhtmlを削除する

$targetProcess = Get-Process -ErrorAction 0 winmergeU
if($targetProcess -eq $null){}else{stop-process $targetProcess}
del -ErrorAction 0 "$savePath\*.htm"



# メインウィンドウ配下を全て表示 (デバッグ用)
#$mainWindow.FindAll($UIASubTreeScope, $UIATrue)  | % {$_.current}  | select name, ControlType , ClassName, LocalizedControlType


#保存先ディレクトリ、比較先元ディレクトリ指定
$savePath = "C:\work\test\"  #htmlのレポートを出力するフォルダ
$aft_path = "C:\work\aft\"   #変更後のファイルが格納されているフォルダ
$bef_path = "C:\work\bef\"   #変更前のファイルが格納されているフォルダ

$aft_files = Get-ChildItem "$aft_path" | Where-Object { ! $_.PSIsContainer } | % {$_.name}
$bef_files = Get-ChildItem "$bef_path" | Where-Object { ! $_.PSIsContainer } | % {$_.name}

$WinMerge = "F:\Program Files\WinMerge\WinMergeU.exe"             #WinMergeU.exeがあるパスを指定


foreach ($aft in $aft_files){
    
    $a = $bef_path+$bef_files[$i]
    $b = $aft_path+$aft
    $filename = [System.IO.Path]::GetFileNameWithoutExtension($bef_files[$i])+"⇔"+[System.IO.Path]::GetFileNameWithoutExtension($aft)+".htm"

    #WINMERGEを起動する
    $targetProcess = & $WinMerge $a $b 
    Sleep -m 2000
    $targetProcess = Get-Process winmergeU
    
    # プロセスからメインウィンドウの AutomationElement を取得
    $mainWindow = $UIAElement::FromHandle($targetProcess.MainWindowHandle)
    
    # メニューバーの[ツール]→[レポートの生成(R)]を開く
    $menuItemHelp = $mainWindow.FindAll($UIASubTreeScope, $UIATrue) | Where-Object {$_.Current.Name -eq "ツール(T)"}
    $menuItemHelp.GetCurrentPattern($UIAExpandPattern).Expand()
    $menuItemVersion = $mainWindow.FindAll($UIASubTreeScope, $UIATrue) | Where-Object {$_.Current.AutomationId -like "Item 32868"}    #レポートの生成(R)にあたるのがItem 32868 ※ツール(T)をExpandした状態でないとIDが見えない
    
    #$mainWindow.FindAll($UIASubTreeScope, $UIATrue)  | % {$_.current}   > "$bef_path\デバッグ出力_bef.txt"   #今ウィンドウで表示されているパラメータをすべて出力。主にAutomationIdで指定してもうまく動作しなかった時に見る。
    
    $menuItemVersion.GetCurrentPattern($UIAInvokePattern).Invoke()
    
    Sleep -m 2000 #ダイアログ表示を待つ
    
    #名前を付けて保存ウィンドウを開く
    #$mainWindow.FindAll($UIASubTreeScope, $UIATrue)  | % {$_.current}  > "$aft_path\デバッグ出力_aft.txt"　　#今ウィンドウで表示されているパラメータをすべて出力。主にAutomationIdで指定してもうまく動作しなかった時に見る。

    $openWnd = Get-UiaWindow -Name '名前を付けて保存';
    Get-UiaEdit $openWnd -AutomationId '41477' -Class 'Edit' -Name 'アドレス'

    Sleep -m 3000 #ダイアログ表示を待つ

    $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 = $filename;
    $saveProcess.Keyboard.KeyPress([WindowsInput.Native.VirtualKeyCode]::RETURN) | Out-Null;
       
    
    Sleep -m 2000 #クローズ完了を待つ
    
    $fontDialog   = $mainWindow.FindAll($UIASubTreeScope, $UIATrue) | Where-Object {$_.Current.automationid -like "1"}
    
    $btnOK        = $fontDialog.FindAll($UIASubTreeScope, $UIATrue) | Where-Object {$_.Current.Name -like "OK"}
    
    $btnOK.GetCurrentPattern($UIAInvokePattern).Invoke()

    stop-process $targetProcess
    $i = $i+1 


}

```


##後々修正したい箇所
「名前を付けて保存」ウィンドウでパスを指定できるのですが、comboboxのIDを指定しても値をセットできませんでした。
ちょっと力業な感じがしますが、ウィンドウを開いてからKeyboard.KeyPressでF4を押して$save_pathを入れてます。
以下その部分の抜粋

```Powershell

    Get-UiaEdit $openWnd -AutomationId '41477' -Class 'Edit' -Name 'アドレス'
    Sleep -m 3000 #ダイアログ表示を待つ

    $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;

```