PowerShellでGUI画面を操作する方法(UI Automation)

PowerShellでGUI画面を操作する方法(UI Automation)。

Windowsでの操作を効率化する場合、コマンドで対応するのが一般的ですが、設定内容によってはコマンドだけでは対応できず、GUIインターフェースの操作(クリックやキー入力など)が必要になる場合があります。そのようなときに標準機能だけで自動化するなら、PowerShellと.NETのUI Automationライブラリを使った方法がおすすめです。

そこでここでは、Windows 11のPowerShellから.NETのUI Automationライブラリを使って、GUI操作を自動化する方法を解説します。

UI Automationとは

UI Automationは、Windows上で実行されているアプリケーションのGUI要素(ボタン、テキストボックス、メニューなど)をプログラムから操作するための.Netの機能で、マウスやキーボードを使った定型操作を効率する(RPA:Robotic Process Automation)用途などで利用されています。

UI Automationは、PowerShellからも.NETのUI Automationライブラリを呼び出すことで利用でき、PowerShellスクリプトでアプリケーション画面の操作やWindowsの設定画面の操作などを自動化できます。

PowerShellスクリプトでUI Automationを使う場合の基本手順は、操作対象のウィンドウを特定>操作対象の要素を特定>指定した要素に応じた操作を実行するという流れで、ウィンドウやボタンなどの要素は名前やIDで特定します。なお、操作対象の要素の名前やIDは「Accessibility Insights」を使って調べることができます。

要素の種類としては、ボタンのクリック・トグルスイッチ・コンボボックスから項目を選択・テキストボックスへの入力などがあります。

使用例1:プロキシ設定の自動化

以下は、Windowsの「設定」>「ネットワークとインターネット」>「プロキシ」の設定画面で「設定を自動的に検出する」をオフに設定する操作のPowerShellスクリプトです。

#UIAutomationを使うための事前設定
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes

$UIAElement   = [System.Windows.Automation.AutomationElement]
$UIATreeScope = [System.Windows.Automation.TreeScope]
$UIACondition = [System.Windows.Automation.PropertyCondition]
$UIAAndCond   = [System.Windows.Automation.AndCondition]

Start-Process "ms-settings:network-status"

#操作対象ウィンドウの補足
$root = $UIAElement::RootElement
$winCond = New-Object $UIACondition($UIAElement::ClassNameProperty, "ApplicationFrameWindow")
$nameCond = New-Object $UIACondition($UIAElement::NameProperty, "設定")
$andCond = New-Object $UIAAndCond($winCond, $nameCond)
$count = 0
while ($count -lt 15) {
  $settingsWin = $root.FindFirst($UIATreeScope::Children, $andCond)
  if ($settingsWin) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}

#操作対象要素「プロキシ」をクリック
$targetCond = New-Object $UIACondition($UIAElement::NameProperty, "プロキシ")
$count = 0
while ($count -lt 15) {
  $invoke = $settingsWin.FindFirst($UIATreeScope::Descendants, $targetCond)
  if ($invoke) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$invokePattern = $invoke.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern)
$invokePattern.Invoke()

#操作対象要素「設定を自動的に検出する」のトグルを切り替え
$targetCond = New-Object $UIACondition($UIAElement::AutomationIdProperty, "SystemSettings_Proxy_AutomaticDetection_ToggleSwitch")
$count = 0
while ($count -lt 15) {
  $toggle = $settingsWin.FindFirst($UIATreeScope::Descendants, $targetCond)
  if ($toggle) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$togglePattern = $toggle.GetCurrentPattern([System.Windows.Automation.TogglePattern]::Pattern)
$currentState = $togglePattern.Current.ToggleState
if ($currentState -eq 'on'){
  $togglePattern.Toggle()
}

使用例2:トラブルシューティング設定の自動化

以下は、Windowsの「設定」>「システム」>「トラブルシューティング」の設定画面で「トラブルシューティングの推奨設定」を「何も実行しない」に設定する操作のPowerShellスクリプトです。

#UIAutomationを使うための事前設定
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes

$UIAElement   = [System.Windows.Automation.AutomationElement]
$UIATreeScope = [System.Windows.Automation.TreeScope]
$UIACondition = [System.Windows.Automation.PropertyCondition]
$UIAAndCond   = [System.Windows.Automation.AndCondition]

Start-Process "ms-settings:troubleshoot"

#操作対象ウィンドウの補足
$root = $UIAElement::RootElement
$winCond = New-Object $UIACondition($UIAElement::ClassNameProperty, "ApplicationFrameWindow")
$nameCond = New-Object $UIACondition($UIAElement::NameProperty, "設定")
$andCond = New-Object $UIAAndCond($winCond, $nameCond)
$count = 0
while ($count -lt 15) {
  $settingsWin = $root.FindFirst($UIATreeScope::Children, $andCond)
  if ($settingsWin) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}

#操作対象要素「トラブルシューティングツールの推奨設定」のコンボボックスを展開
$targetCond = New-Object $UIACondition($UIAElement::AutomationIdProperty, "SystemSettings_Troubleshoot_RecommendedTroubleshooting_UserPreference_ComboBox")
$count = 0
while ($count -lt 15) {
  $comboBox = $settingsWin.FindFirst($UIATreeScope::Descendants, $targetCond)
  if ($comboBox) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$expandCollapse = $comboBox.GetCurrentPattern([System.Windows.Automation.ExpandCollapsePattern]::Pattern)
$expandCollapse.Expand()

#操作対象要素のコンボボックスから「何も実行しない」を選択
$targetCond = New-Object $UIACondition($UIAElement::NameProperty, "何も実行しない")
$count = 0
while ($count -lt 15) {
  $itemToSelect = $comboBox.FindFirst($UIATreeScope::Descendants, $targetCond)
  if ($itemToSelect) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$selectionItem = $itemToSelect.GetCurrentPattern([System.Windows.Automation.SelectionItemPattern]::Pattern)
$selectionItem.Select()

使用例3:コンピューター名の変更

以下は、Windowsの「設定」>「システム」>「バージョン情報」画面からコンピューター名を変更する操作のPowerShellスクリプトです。

なお、コンピューター名の変更はPowerShellコマンドレット「Rename-Computer」で変更できるので、以下のようなスクリプトを使ってわざわざGUI画面から変更するメリットはありませんが。。

#UIAutomationを使うための事前設定
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes

$UIAElement   = [System.Windows.Automation.AutomationElement]
$UIATreeScope = [System.Windows.Automation.TreeScope]
$UIACondition = [System.Windows.Automation.PropertyCondition]
$UIAAndCond   = [System.Windows.Automation.AndCondition]

Start-Process "ms-settings:about"

#操作対象ウィンドウの補足
$root = $UIAElement::RootElement
$winCond = New-Object $UIACondition($UIAElement::ClassNameProperty, "ApplicationFrameWindow")
$nameCond = New-Object $UIACondition($UIAElement::NameProperty, "設定")
$andCond = New-Object $UIAAndCond($winCond, $nameCond)
$count = 0
while ($count -lt 15) {
  $settingsWin = $root.FindFirst($UIATreeScope::Children, $andCond)
  if ($settingsWin) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}

#操作対象要素「このPCの名前を変更」ボタンをクリック
$targetCond = New-Object $UIACondition($UIAElement::AutomationIdProperty, "SystemSettings_PCSystem_RenamePC_Button")
$count = 0
while ($count -lt 15) {
  $invoke = $settingsWin.FindFirst($UIATreeScope::Descendants, $targetCond)
  if ($invoke) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$invokePattern = $invoke.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern)
$invokePattern.Invoke()

#操作対象要素のテキストボックスに新しいPC名「PC-888」を入力
$targetCond1 = New-Object $UIACondition($UIAElement::AutomationIdProperty, "NewComputerNameTextBox")
$targetCond2 = New-Object $UIACondition($UIAElement::ControlTypeProperty, [System.Windows.Automation.ControlType]::Edit)
$andCond = New-Object $UIAAndCond($targetCond1, $targetCond2)
$count = 0
while ($count -lt 15) {
  $edit = $settingsWin.FindFirst($UIATreeScope::Descendants, $andCond)
  if ($edit) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$valueitemPattern = $edit.GetCurrentPattern([System.Windows.Automation.ValuePattern]::Pattern)
$valueitemPattern.SetValue('PC-888')

#操作対象要素「次へ」ボタンをクリック
$targetCond1 = New-Object $UIACondition($UIAElement::AutomationIdProperty, "NextButton")
$targetCond2 = New-Object $UIACondition($UIAElement::NameProperty, "次へ")
$andCond = New-Object $UIAAndCond($targetCond1, $targetCond2)
$count = 0
while ($count -lt 15) {
  $invoke = $settingsWin.FindFirst($UIATreeScope::Descendants, $andCond)
  if ($invoke) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$invokePattern = $invoke.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern)
$invokePattern.Invoke()

#操作対象要素「今すぐ再起動する」ボタンをクリック
$targetCond1 = New-Object $UIACondition($UIAElement::AutomationIdProperty, "NextButton")
$targetCond2 = New-Object $UIACondition($UIAElement::NameProperty, "今すぐ再起動する")
$andCond = New-Object $UIAAndCond($targetCond1, $targetCond2)
$count = 0
while ($count -lt 15) {
  $invoke = $settingsWin.FindFirst($UIATreeScope::Descendants, $andCond)
  if ($invoke) {
    break
  }
  Start-Sleep -Seconds 1
  $count++
}
$invokePattern = $invoke.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern)
$invokePattern.Invoke()

あとがき

Windowsの設定や、アプリやブラウザの操作でコマンドでは対応できないときに、UI Automationを使ったGUI操作で対応する方法が役立つときもあるでしょう。ご活用あれ。