ユーザーインターフェース自動化

コマンド ラインから実行中のWindows アプリケーションを検査して操作します。 UI テスト、デバッグ、自動化のために AI エージェントと開発者によって使用されます。

概要

winapp ui には、Windows アプリ UI を検査および操作するためのコマンドが用意されています。 Windows UI オートメーション (UIA) を使用します。 WPF、WinForms、Win32、Electron、WinUI 3 など、任意のWindows アプリで動作します。 ほとんどのコマンドは、UIA パターン (入力インジェクションなし) を通じてアプリを駆動します。 ui click は例外であり、 InvokePatternをサポートしていないコントロールには実際のマウス シミュレーションを使用します。

クイック スタート

# Connect to any app and see its UI tree
winapp ui inspect -a notepad

# Find specific elements
winapp ui search Button -a notepad

# Activate an element
winapp ui invoke Close -a notepad

# Take a screenshot
winapp ui screenshot -a notepad

アプリのターゲット設定

プロセス名別

winapp ui inspect -a notepad
winapp ui inspect -a slack            # auto-picks visible window for multi-process apps
winapp ui inspect -a imageresizer     # partial match: finds PowerToys.ImageResizer

ウィンドウ のタイトル別

winapp ui inspect -a "LICENSE - Notepad"
winapp ui inspect -a "Fix WinApp"     # partial title match

PID 別

winapp ui inspect -a 12345

HWND によって (安定 — タブ/タイトルの変更は存続します)

# Discover HWNDs
winapp ui list-windows -a Terminal
  → HWND 985238: "🤖 Testing" (WindowsTerminal, PID 21228)
  → HWND 131906: "Fix WinApp" (WindowsTerminal, PID 21228)

# Target specific window
winapp ui inspect -w 131906
winapp ui screenshot -w 131906

検出には -a を使用し、安定したターゲット設定には -w します。 -aが複数のウィンドウと一致する場合、コマンドは選択できるように HWND で一覧表示します。

セレクター

検査/検索出力の [brackets] に示されているセレクターを使用して要素をターゲットします。 セレクターには次の 3 種類があります。

Selector 意味 Example
MinimizeButton AutomationId (一意の場合に表示されます — 安定しています。推奨) winapp ui invoke MinimizeButton -a myapp
btn-close-d1a0 セマンティック スラッグ (一意の AutomationId がない場合に表示されます) winapp ui invoke btn-close-d1a0 -a myapp
Submit Name/AutomationId に対するプレーンテキスト検索 (大文字と小文字を区別しない部分文字列) winapp ui invoke Submit -a myapp

AutomationId セレクターは、 開発者セット識別子 (XAML でAutomationProperties.AutomationId )。 UI ツリー全体で AutomationId が一意である場合、 inspect し、セレクターとして直接表示 search 。これらは、レイアウトの変更、ローカライズ、ツリーの再構築に耐えられます。

一意の AutomationId が存在しない場合、スラッグ セレクター (btn-close-d1a0 など) が生成されます。 形式: prefix-name-hash。 ハッシュは要素 ID を検証しますが、UI の変更後に古くなる可能性があります。

出力形式を検査する

inspect コマンドは、色付きの出力 (シアンのセレクター、緑の名前、灰色のメタデータ) を持つ要素ツリーを表示します。

TabView Tab (0,-1 1200x48)
  TabListView List (4,-1 1100x48)
    tab-newtab-5f5b TabItem "New Tab" (14,-1 200x48)
  NewTabButton SplitButton "New Tab" [collapsed] (1104,5 96x36)
Found 10 elements (--depth 3). Use the first token as selector, e.g.: winapp ui invoke TabView -a terminal

各行の 最初の単語 はセレクターであり、他の ui コマンドと共に使用します。 要素に一意の AutomationId がある場合は、直接使用されます (たとえば、 TabViewNewTabButton)。 一意の AutomationId が存在しない場合は、生成されたスラッグが使用されます (例: tab-newtab-5f5b)。

セマンティック スラッグ

ナメクジは、次の形式 prefix-normalizedname-hash 使用します。

  • prefix — 3 文字の型の省略形 (btn、txt、chk、cmb、itm、tab、img、lbl、pn、win、grp、lnk、mnu など)
  • normalizedname — AutomationId (推奨) または Name の小文字の英数字(最大 15 文字)
  • hash — 要素の RuntimeId の 4 文字の 16 進ハッシュ (要素 ID を検証します)

スラッグはシェルセーフ (特殊文字なし)、一意であり、引数として直接使用できます。 ハッシュは、制約の検出を提供します。要素が置き換えられた場合は、"要素が変更された可能性があります。 検査を再実行します。"

name または AutomationId を持たない要素には、プレフィックス + ハッシュのみが表示されます (例: pn-c8a3)。

複数の一致のあいまいさを解消する

inspect / search出力からのスラッグは一意ですが、レイアウトの変更間で変更される可能性があります。複数の一致する場合は、プレーン型の名前またはテキストで使用します。 セレクターがあいまいな場合、CLI はすべての一致をそのナメクジと共に出力するため、適切なものを選択し、そのスラッグで再実行できます。

winapp ui search Button -a myapp            # shows: btn-ok-a1b2 "OK", btn-cancel-c3d4 "Cancel"
winapp ui invoke btn-ok-a1b2 -a myapp       # invoke using slug (preferred)
winapp ui invoke btn-cancel-c3d4 -a myapp   # invoke the other Button by its slug

プレーンテキストを使用して要素を検索します。特別な構文は必要ありません。

winapp ui search Minimize -a notepad        # finds elements with "Minimize" in Name or AutomationId
winapp ui search Close -a notepad           # case-insensitive substring match
winapp ui invoke Minimize -a notepad        # search + invoke in one step (disambiguates if needed)
winapp ui search "Save" -a notepad          # find elements containing "Save"
winapp ui search "error" -a myapp           # case-insensitive match

テキスト検索が複数の要素と一致する場合 (たとえば、Group、Button、Text がすべて同じ名前を共有する SettingsExpander など)、CLI は呼び出し可能な唯一の要素を自動的に選択します。 複数の呼び出し可能な場合は、すべての一致をスラッグで一覧表示します。

呼び出し不可能な検索結果 (たとえば、ボタン内の TextBlock) の場合、検索では、最も近い 呼び出し可能な先祖 ( invokeで使用できる親要素) が自動的に表示されます。 これは、すべての検索セレクターで機能します。

  lbl-savechanges-a1b2 "Save changes" (120,40 80x20)
        ^ invoke via: btn-save-c3d4 "Save"

サーフェス セレクターは直接使用できます。

winapp ui invoke btn-save-c3d4 -a myapp    # invoke the parent Button

コマンド

状態

アプリに接続し、接続情報を表示します。

winapp ui status -a notepad
winapp ui status -a notepad --json

検査

UI 要素ツリーを表示します。 出力は、階層の 2 スペースインデントを持つセマンティック スラッグを示しています。

winapp ui inspect -a notepad                    # full window tree, depth 3
winapp ui inspect -a notepad --depth 5          # deeper tree
winapp ui inspect txt-searchbox-e5f6 -a notepad # subtree rooted at element
winapp ui inspect --ancestors btn-close-d1a2 -a notepad  # walk up from element to root
winapp ui inspect -a myapp --interactive        # invokable elements only, auto-depth 8
winapp ui inspect -a myapp --hide-disabled      # hide disabled elements
winapp ui inspect -a myapp --hide-offscreen     # hide offscreen elements

出力例 (既定値):

win-aidevgalleryp-f1a3 "AI Dev Gallery Preview" (94,206 1280x1023)
  pn-c8a3 (102,207 1264x1014)
    btn-minimize-d1a0 "Minimize" (1222,206 48x48)
    btn-maximize-e2b1 "Maximize" (1270,206 48x48)
    itm-samples-3f2c "Samples" (102,330 72x62)

出力例 (--interactive — 呼び出し可能な要素のみ、フラット リスト):

btn-minimize-d1a0 "Minimize" (1222,206 48x48)
btn-maximize-e2b1 "Maximize" (1270,206 48x48)
btn-close-d1a2 "Close" (1318,206 48x48)
itm-home-7b3e "Home" (102,268 72x62)
itm-samples-3f2c "Samples" (102,330 72x62)
itm-models-9a4f "Models" (102,392 72x62)

要素には、次の状態マーカーが表示される場合があります。

  • [on] / [off] / [indeterminate] — トグル/チェックボックスの状態
  • [collapsed] / [expanded] — ツリー、コンボ ボックス、メニュー項目の展開/折りたたみ状態
  • [scroll:v] / [scroll:h] / [scroll:vh] — スクロール可能なコンテナー (垂直、水平、またはその両方)
  • [offscreen] — 要素が画面に表示されない
  • [disabled] — 要素が有効になっていません
  • value="..." 編集可能な要素の現在のテキスト コンテンツ (名前と異なる場合)

セレクターに一致する要素を検索します。 セマンティック スラッグを示す出力:

winapp ui search Button -a notepad              # all buttons
winapp ui search Close -a notepad               # finds elements with "Close" in name
winapp ui search SearchBox -a notepad           # finds elements with "SearchBox" in name or AutomationId
winapp ui search Button --max 10 -a notepad     # limit results

出力例:

  btn-minimize-d1a0 "Minimize" (1222,206 48x48)
  btn-maximize-e2b1 "Maximize" (1270,206 48x48)
  btn-close-d1a2 "Close" (1318,206 48x48)

出力に表示されるスラッグ (例: btn-minimize-d1a0) は、他のコマンドで直接使用できます。

winapp ui invoke btn-minimize-d1a0 -a notepad

get-property

要素からプロパティ値を読み取ります。 パターン固有の状態 (ToggleState、Value、IsSelected など) が含まれます。

winapp ui get-property btn-submit-7a90 -a myapp              # all properties
winapp ui get-property chk-checkbox-b2c3 -p ToggleState -a myapp   # checkbox state
winapp ui get-property txt-textbox-a4b1 -p Value -a myapp          # current text value
winapp ui get-property cmb-combobox-d5e6 -p ExpandCollapseState -a myapp  # expanded or collapsed

スクリーンショット

ウィンドウまたは要素を PNG としてキャプチャします。 複数のウィンドウ (アプリと開いているダイアログなど) が存在する場合、各ウィンドウが結合された単一の PNG に合成されます。

winapp ui screenshot -a notepad                     # saves screenshot.png in cwd
winapp ui screenshot -a notepad --output my.png     # custom filename
winapp ui screenshot -a notepad --json              # returns file path as JSON
winapp ui screenshot -w 131906                      # target specific HWND (+ its dialogs)
winapp ui screenshot txt-searchbox-e5f6 -a myapp          # crop to element bounds
winapp ui screenshot -a myapp --capture-screen      # capture from screen (includes popups/overlays)

ダイアログまたはポップアップを開くと、すべてのウィンドウが 1 つの PNG に合成されるため、1 つの画像で完全な UI 状態を確認できます。

ポップアップ メニュー、ドロップダウン、ポップアップ、またはヒント オーバーレイをキャプチャする必要がある場合は、 --capture-screen を使用します。 --capture-screen モード (および空白フレームが検出された後に再試行する場合) では、ターゲット ウィンドウが最初にフォアグラウンドに移動されます。通常のウィンドウ キャプチャはウィンドウを移動しません。

呼び出す

プログラムによって要素をアクティブにします (クリック ボタン、トグル チェック ボックス、コンボ ボックスの展開)。

winapp ui invoke btn-submit-7a90 -a myapp             # by slug from inspect
winapp ui invoke btn-submit-a1b2 -a myapp  # by slug from inspect/search
winapp ui invoke cmb-sizecombobox-b4c5 -a myapp # expand combo box

パターンを順番に試行します。InvokePattern → TogglePattern → SelectionItemPattern → ExpandCollapsePattern です。

クリックする

マウス シミュレーションを使用して、画面座標の要素をクリックします。 これは、 InvokePattern をサポートしていないコントロール (列ヘッダー、リスト アイテムなど) に使用します。

winapp ui click btn-column1-a3f2 -a myapp              # single click by slug
winapp ui click "Column1" -a myapp                      # single click by text search
winapp ui click btn-column1-a3f2 -a myapp --double      # double-click
winapp ui click btn-column1-a3f2 -a myapp --right       # right-click

set-value

編集可能な要素 (TextBox/ComboBox の場合はテキスト、スライダーの場合は数値) に値を設定します。

winapp ui set-value txt-textbox-a4b1 "Hello world" -a notepad
winapp ui set-value sld-volume-b2c3 75 -a myapp

get-value

要素から現在の値を読み取る。 スマート フォールバック チェーンを使用します。TextPattern (RichEditBox、Document) → ValuePattern (TextBox、Slider) → SelectionPattern (ComboBox、RadioButton、TabView) →名前 (ラベル)。

winapp ui get-value doc-texteditor-53ad -a notepad          # read full document text
winapp ui get-value SearchBox -a myapp                      # read TextBox content
winapp ui get-value CmbTheme -a myapp                       # read ComboBox selected item
winapp ui get-value sld-volume-b2c3 -a myapp                # read Slider value
winapp ui get-value lbl-title-a1b2 -a myapp --json          # JSON: { "elementId": "...", "text": "..." }

フォーカス

キーボード フォーカスを要素に移動します。

winapp ui focus txt-textbox-a4b1 -a notepad

scroll-into-view

要素を表示領域までスクロールします。

winapp ui scroll-into-view itm-targetitem-c3d4 -a myapp

wait-for

要素が表示されるか、消えるか、値がターゲットに到達するまで待ちます。

winapp ui wait-for Button -a myapp --timeout 5000                       # wait for any button
winapp ui wait-for btn-submit-7a90 -a myapp --timeout 5000             # wait for specific element
winapp ui wait-for CounterDisplay -a myapp --value "5" --timeout 5000  # wait for element value (smart fallback)
winapp ui wait-for lbl-status -a myapp --property Name --value "Done" --timeout 5000  # wait for specific property
winapp ui wait-for btn-submit-a1b2 --gone -a myapp --timeout 2000      # wait for element to disappear
winapp ui wait-for lbl-status -a myapp --value "Done" --contains       # substring match instead of exact equality

スクロール

コンテナー要素をスクロールします。 search scrollを持つスクロール可能なコンテナーを検索します。[scroll:v] (垂直) または[scroll:h] (水平) マーカーを探します。

# Find which elements are scrollable and in which direction
winapp ui search scroll -a myapp
#   pn-scrollview-bfef Pane "scrollView" [scroll:v] (main content, vertical)
#   pn-scrollviewer-bfb1 Pane "scrollViewer" [scroll:h] (horizontal list)

# Scroll the main content down
winapp ui scroll pn-scrollview-bfef --direction down -a myapp

# Jump to top/bottom
winapp ui scroll pn-scrollview-bfef --to bottom -a myapp

# If you target an element that's not scrollable, scroll walks up to find the nearest scrollable parent
winapp ui scroll itm-someitem-a1b2 --direction down -a myapp

get-focused

現在キーボード フォーカスがある要素を表示します。

winapp ui get-focused -a myapp

list-windows

ポップアップやダイアログなど、アプリのすべての表示ウィンドウを一覧表示します。

winapp ui list-windows -a imageresizer
winapp ui list-windows -a Terminal
winapp ui list-windows                                      # all windows (no filter)

フレームワークのサポート

フレームワーク 検査 検索 呼び出す set-value スクリーンショット
WPF ✅ 完全なツリー ✅ すべてのプロパティ ✅ すべてのパターン
WinForms
Win32 の
WinUI 3
電子 ⚠️ Chromium ツリー ⚠️ 制限あり ⚠️ 異なる ⚠️ 異なる
Flutter ⚠️ 基本 ⚠️ 基本 ❌ 最小限

Troubleshooting

エラー 原因 ソリューション
"実行中のアプリが見つかりません" アプリが実行されていないか、名前の不一致 プロセス名を確認するか、PID を使用する
"複数のウィンドウの一致" あいまいな -a 表示されているオプションの -w <HWND> を使用する
"複数のウィンドウがある" プロセスに複数のウィンドウがある -w <HWND>を使用して特定のターゲットを設定する
"セレクターが一致した N 個の要素" あいまいなレガシ セレクター inspect出力からスラッグを使用するか、レガシ セレクターに[1][0]を追加する
"要素が変更された可能性があります" Slug ハッシュが現在の要素と一致しない inspectまたはsearchを再実行して新鮮なナメクジを取得する
"どの呼び出しパターンもサポートしていません" 要素を呼び出すことはできません 要素で inspect を使用して、呼び出し可能な子を検索する
"UIA ウィンドウが見つかりません" UIA でプロセスが表示されない list-windowsを使用して HWND を検索し、次に-w
"Window has zero size" ウィンドウが最小化されている アプリは自動的に復元されます
スクリーンショットにないポップアップ/ドロップダウン PrintWindow でオーバーレイがキャプチャされない --capture-screen フラグを使用する

一般的なパターン

winapp ui invoke btn-settings-a1b2 -a myapp          # click a button
winapp ui wait-for pn-settingspage-c3d4 -a myapp    # wait for page to load
winapp ui screenshot -a myapp --output settings.png  # verify visually

テキストを検索してその親を呼び出す

# Search shows invokable ancestor; invoke auto-walks to it
winapp ui invoke 'Save changes' -a myapp

# Or search first to see what matches, then invoke
winapp ui search "Save changes" -a myapp; winapp ui invoke btn-save-c3d4 -a myapp

重複する要素のあいまいさを解消する

winapp ui search '#Image' -a myapp; winapp ui invoke itm-image-a2b3 -a myapp

ポップアップ オーバーレイを含むスクリーンショット

winapp ui set-value txt-searchbox-e5f6 "query" -a myapp; winapp ui screenshot -a myapp --capture-screen
winapp ui invoke btn-settings-a1b2 -a myapp; winapp ui wait-for pn-settingspage-c3d4 -a myapp --timeout 3000; winapp ui screenshot -a myapp -o settings.png

検出、クリック、確認

winapp ui inspect -a myapp --interactive; winapp ui invoke btn-submit-7a90 -a myapp; winapp ui screenshot -a myapp

[ファイル] ダイアログの操作

ファイルの開く/保存ダイアログは、UIA をサポートする標準的なWindows ダイアログです。

# Trigger the dialog, find it, type the path, confirm
winapp ui invoke btn-openfilebtn-a2b3 -a myapp
winapp ui list-windows -a myapp                                      # find dialog HWND
winapp ui set-value txt-1148-c4d5 "C:\path\to\file.png" -w <dialog-hwnd>
winapp ui invoke btn-open-e6f7 -w <dialog-hwnd>

inspect -w <dialog-hwnd> --interactiveを使用して、特定のダイアログの実際のナメクジを検出します。

チェーンの ; 理由 ( &&ではない)

PowerShell の && 演算子は、ネイティブ CLI が stderr に書き込んだり、ANSI エスケープ シーケンスを使用したりするとフリーズする可能性があります。 代わりに ; を使用します。各コマンドは無条件に実行され、このデッドロックを回避します。 これはエージェント ワークフローにも適しています。通常は、呼び出しに 0 以外の終了があった場合でも、スクリーンショットを実行する必要があります。

CI テスト パターン

スモーク テストと UI 検証には、CI パイプライン (GitHub Actions、Azure DevOps) で winapp ui コマンドを使用します。 wait-for --property--valueはアサーションとして機能します。タイムアウト時に終了コード 1 が返され、CI ステップが自動的に失敗します。

GitHub Actionsで起動してテストする

steps:
  - name: Build
    run: dotnet build MyApp.csproj -c Debug -p:Platform=x64

  - name: Launch and test
    run: |
      $result = winapp run .\bin\x64\Debug\net8.0-windows10.0.26100.0\win-x64 --detach --json | ConvertFrom-Json
      $appPid = $result.ProcessId

      # Wait for window to initialize
      winapp ui wait-for "Main Window" -a $appPid --timeout 30000

      # Run tests — each wait-for exits non-zero on failure
      winapp ui invoke "Login" -a $appPid
      winapp ui wait-for "Dashboard" -a $appPid --timeout 10000
      winapp ui screenshot -a $appPid -o dashboard.png

Assert 要素の状態 wait-for

wait-for --value 要素の値が、 get-value と同じスマート フォールバック (TextPattern → ValuePattern → SelectionPattern → Name) を使用して、予期される文字列と一致するまでポーリングします。 マッチ時に終了コード 0 を返し、タイムアウト時に終了コード 1 を返します。CI に優しいアサーションになります。 代わりに、 --property を使用して特定の UIA プロパティを確認します。

# Assert: button click updated the counter (smart value fallback — works for TextBlock, TextBox, etc.)
winapp ui invoke "Counter Button" -a $pid
winapp ui wait-for "Counter Display" -a $pid --value "Count: 1" -t 5000

# Assert: text input was accepted
winapp ui set-value "Search Box" "hello world" -a $pid
winapp ui wait-for "Search Box" -a $pid --value "hello world" -t 3000

# Assert: checkbox was toggled (use --property for specific UIA properties)
winapp ui invoke "Dark Mode" -a $pid
winapp ui wait-for "Dark Mode" -a $pid --property ToggleState --value "On" -t 3000

# Assert: navigation happened (new page appeared)
winapp ui invoke "Settings" -a $pid
winapp ui wait-for "Settings Page" -a $pid -t 10000

# Assert: dialog was dismissed (element disappeared)
winapp ui invoke "Close" -a $pid
winapp ui wait-for "Dialog Title" -a $pid --gone -t 5000

JSON 出力を使用してアサートする

より複雑なアサーションには、PowerShell または jq で --json を使用します。

--json モードでのsearchおよびwait-forの終了コード コントラクト: 要素が一致しない (search) か、待機タイムアウト (wait-for) 場合、コマンドは完全に解析可能な結果エンベロープを stdout ({ "matchCount": 0, ... } または { "found": false, "timedOut": true, ... }) に書き込み、終了コード 1 を返します。 --json モードでは Stderr が空です (ロガー出力は抑制されます)。 エンベロープ フィールドまたは $LASTEXITCODE で分岐します。これは、より人間工学に基づくものに応じて異なります。

# Assert: search found exactly one match
$result = winapp ui search "Submit" -a $pid --json | ConvertFrom-Json
if ($result.matchCount -ne 1) { throw "Expected 1 Submit button, found $($result.matchCount)" }

# Assert: element has expected properties
# inspect --json returns { windows: [{ hwnd, title, elements: [...] }] };
# each window's elements[] is the nested tree (children rendered via .children).
$tree = winapp ui inspect "Counter Display" -a $pid --json | ConvertFrom-Json
$counter = $tree.windows[0].elements[0]
if ($counter.name -ne "Count: 3") { throw "Counter value wrong: $($counter.name)" }

完全スモーク テストの例

# Launch
$app = winapp run .\build-output --detach --json | ConvertFrom-Json

# Verify app loaded
winapp ui wait-for "Main Page" -a $app.ProcessId -t 30000

# Interact and assert
winapp ui invoke "Add Item" -a $app.ProcessId
winapp ui set-value "Item Name" "Test Item" -a $app.ProcessId
winapp ui invoke "Save" -a $app.ProcessId
winapp ui wait-for "Test Item" -a $app.ProcessId -t 5000              # assert item appeared in list
winapp ui wait-for "Save" -a $app.ProcessId --gone -t 3000            # assert save dialog closed

# Visual verification
winapp ui screenshot -a $app.ProcessId -o smoke-test.png