UI-automatisering

Inspektera och interagera med att köra Windows program från kommandoraden. Används av AI-agenter och utvecklare för gränssnittstestning, felsökning och automatisering.

Översikt

winapp ui innehåller kommandon för att inspektera och interagera med Windows app-UIs. Använder Windows UI Automation (UIA). Fungerar med alla Windows appar – WPF, WinForms, Win32, Electron och WinUI 3. De flesta kommandon kör appen via UIA-mönster (ingen inmatning); ui click är undantaget och använder verklig mussimulering för kontroller som inte stöder InvokePattern.

Snabbstart

# 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

Rikta in sig på appar

Efter processnamn

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

Efter fönsterrubrik

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

Efter PID

winapp ui inspect -a 12345

Efter HWND (stabil – överlever tab-/titeländringar)

# 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

Används -a för identifiering -w för stabil inriktning. När -a matchar flera fönster listar kommandot dem med HWND:er som du kan välja.

Väljare

Målelement med väljaren som visas i [brackets] inspektera/söka utdata. Det finns tre typer av väljare:

Selector Meaning Example
MinimizeButton AutomationId (visas när det är unikt – stabilt, prioriterat) winapp ui invoke MinimizeButton -a myapp
btn-close-d1a0 Semantisk snigel (visas när inget unikt AutomationId) winapp ui invoke btn-close-d1a0 -a myapp
Submit Oformaterad textsökning mot Namn/AutomationId (skiftlägesokänslig understräng) winapp ui invoke Submit -a myapp

AutomationId-väljare är identifierare för utvecklaruppsättningar (AutomationProperties.AutomationId i XAML). När ett AutomationId är unikt i hela användargränssnittsträdet inspect och search visar det direkt som väljare – dessa överlever layoutändringar, lokalisering och trädomstrukturering.

Snigelväljare (t.ex. btn-close-d1a0) genereras när det inte finns något unikt AutomationId. Format: prefix-name-hash. Hashen validerar elementidentiteten men kan bli inaktuell efter ändringar i användargränssnittet.

Granska utdataformat

Kommandot inspect visar elementträdet med färgade utdata (väljare i cyan, namn i grönt, metadata i grått):

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

Det första ordet på varje rad är väljaren – använd det med andra ui kommandon. När ett element har ett unikt AutomationId används det direkt (t.ex. TabView, NewTabButton). När det inte finns något unikt AutomationId används en genererad snigel (t.ex. tab-newtab-5f5b).

Semantiska sniglar

Sniglar använder formatet: prefix-normalizedname-hash där:

  • prefix – förkortning av 3-bokstavstyp (btn, txt, chk, cmb, itm, tab, img, lbl, pn, win, grp, lnk, mnu osv.)
  • normalizedname – gemener alfanumeriskt från AutomationId (föredraget) eller Namn, max 15 tecken
  • hash – 4-teckens hex-hash för elementets RuntimeId (validerar elementidentitet)

Sniglar är skalsäkra (inga specialtecken), unika och kan användas direkt som argument. Hashen ger föråldringsidentifiering – om elementet har ersatts får du: "Elementet kan ha ändrats. Kör om inspektionen."

Element utan namn eller AutomationId visar endast prefix + hash (t.ex. pn-c8a3).

Tvetydiga flera matchningar

Sniglar från inspect/search utdata är unika, men kan ändras mellan layoutändringar – använd dem över oformaterade typnamn eller text när flera matchningar. När en väljare är tvetydig skriver CLI ut alla matchningar med sina sniglar så att du kan välja rätt och köra igen med den snigeln.

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

Använd oformaterad text för att söka efter element – ingen särskild syntax krävs:

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

När en textsökning matchar flera element (t.ex. InställningarExpander där grupp, knapp och text alla delar samma namn) väljer CLI automatiskt det enda anropsbara elementet. Om flera kan anropas visas alla matchningar med sniglar.

För sökresultat som inte kan anropas (t.ex. en TextBlock inuti en knapp) visas automatiskt den närmaste anropsbara överordnad - det överordnade elementet som du kan använda med invoke. Detta fungerar för alla sökväljare:

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

Väljaren som visas kan användas direkt:

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

Commands

status

Anslut till en app och visa anslutningsinformation.

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

Inspektera

Visa elementträdet för användargränssnittet. Utdata visar semantiska sniglar med indrag med två blanksteg för hierarki:

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

Exempelutdata (standard):

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)

Exempelutdata (--interactive – endast anropsbara element, platt lista):

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)

Element kan visa dessa tillståndsmarkörer:

  • [on] / [off] / [indeterminate] — växla/kryssrutetillstånd
  • [collapsed] / [expanded] — expandera/komprimera tillstånd för träd, kombinationsrutor, menyalternativ
  • [scroll:v] / [scroll:h] / [scroll:vh] — rullningsbar container (lodrät, vågrät eller båda)
  • [offscreen] — elementet visas inte på skärmen
  • [disabled] — elementet är inte aktiverat
  • value="..." — aktuellt textinnehåll för redigerbara element (när det skiljer sig från Namn)

Hitta element som matchar en väljare. Utdata visar semantiska sniglar:

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

Exempel på utdata:

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

Sniglar som visas i utdata (t.ex. btn-minimize-d1a0) kan användas direkt med andra kommandon:

winapp ui invoke btn-minimize-d1a0 -a notepad

get-property

Läsa egenskapsvärden från ett element. Innehåller mönsterspecifikt tillstånd (ToggleState, Value, IsSelected osv.).

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

skärmbild

Avbilda ett fönster eller element som PNG. När det finns flera fönster (t.ex. app + öppen dialogruta) är de sammansatta i en enda PNG med varje fönster insytt.

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)

När dialogrutor eller popup-fönster är öppna, är alla fönster sammansatta i en PNG så att du kan se det fullständiga användargränssnittstillståndet i en enda bild.

Använd --capture-screen när du behöver samla in popup-menyer, listrutor, utfällbara objekt eller knappbeskrivningsöverlägg. I --capture-screen läge (och när ett nytt försök görs efter att en tom bildruta har identifierats) förs målfönstret först till förgrunden. Normala fönsterinsamlingar flyttar inte fönstret.

Åberopa

Aktivera ett element programmatiskt (klicka på knappen, växla kryssrutan, expandera kombinationsrutan).

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

Försöker mönster i ordning: InvokePattern → TogglePattern → SelectionItemPattern → ExpandCollapsePattern.

click

Klicka på ett element vid skärmkoordinaterna med hjälp av mussimulering. Använd detta för kontroller som inte stöder InvokePattern (t.ex. kolumnrubriker, listobjekt).

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

Ange ett värde för ett redigerbart element (text för TextBox/ComboBox, tal för Skjutreglage).

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

get-value

Läs det aktuella värdet från ett element. Använder en smart återställningskedja: TextPattern (RichEditBox, Document) → ValuePattern (TextBox, Slider) → SelectionPattern (ComboBox, RadioButton, TabView) → Name (labels).

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": "..." }

focus

Flytta tangentbordsfokus till ett element.

winapp ui focus txt-textbox-a4b1 -a notepad

bläddra till vyn

Rulla ett element till det synliga området.

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

vänta på

Vänta tills ett element visas, försvinner eller har ett värde som når ett mål.

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

Bläddra

Rulla ett containerelement. Hitta rullningsbara containrar med search scroll – leta [scroll:v] efter (lodräta) eller [scroll:h] (vågräta) markörer.

# 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

Visa elementet som för närvarande har tangentbordsfokus.

winapp ui get-focused -a myapp

list-windows

Visa en lista över alla synliga fönster för en app, inklusive popup-fönster och dialogrutor.

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

Ramverksstöd

Ramverk Inspektera search Åberopa set-value skärmbild
WPF ✅ Fullständigt träd ✅ Alla egenskaper ✅ Alla mönster
WinForms (på engelska)
Win32
WinUI 3
Elektron ⚠️ Kromträd ⚠️ Begränsad ⚠️ Varierar ⚠️ Varierar
Flutter ⚠️ Grundläggande ⚠️ Grundläggande ❌ Minimal

Felsökning

Error Orsak Lösning
"Ingen app som körs hittades" Appen körs inte eller namnmatchningsfel Kontrollera processnamnet eller använd PID
"Flera fönster matchar" Tvetydigt -a värde Använd -w <HWND> från de angivna alternativen
"har flera fönster" Processen har flera fönster Använd -w <HWND> för att rikta in dig på en specifik
"Väljaren matchade N-element" Tvetydig äldre väljare Använda sniglar från inspect utdata eller lägg till [0]i [1] äldre väljare
"Elementet kan ha ändrats" Snigelhash matchar inte aktuellt element inspect Kör igen eller search för att få nya sniglar
"stöder inte något anropsmönster" Det går inte att anropa elementet Använd inspect på -elementet för att hitta ett anropsbart underordnat objekt
"Inget UIA-fönster hittades" UIA kan inte se processen Använd list-windows för att hitta HWND och sedan -w
"Fönstret har noll storlek" Fönstret minimeras Appen återställs automatiskt
Popup-/listruta finns inte i skärmbilden PrintWindow samlar inte in överlägg Använd --capture-screen flagga

Vanliga mönster

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

Hitta text och anropa dess överordnade

# 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

Tvetydiga duplicerade element

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

Skärmbild med popup-överlägg

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

Identifiera, klicka och verifiera

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

Interaktion med fildialogruta

Dialogrutan Öppna/spara filer är standarddialogrutor för Windows med UIA-stöd:

# 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>

Använd inspect -w <dialog-hwnd> --interactive för att identifiera de faktiska sniglarna för en specifik dialogruta.

Varför ; för länkning (inte &&)

PowerShell-operatorn kan låsas && när ett inbyggt CLI skriver till stderr eller använder ANSI-escape-sekvenser. Använd ; i stället – det kör varje kommando villkorslöst och undviker det här dödläget. Det här är också bättre för agentarbetsflöden: du vill vanligtvis att skärmbilden ska köras även om anropan hade en avslut som inte var noll.

CI-testmönster

Använd winapp ui-kommandon i CI-pipelines (GitHub Actions, Azure DevOps) för röktester och UI-validering. wait-for med --property och --value fungerar som ett intyg – det returnerar slutkod 1 vid timeout, misslyckas CI-steget automatiskt.

Starta och testa i 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-elementtillstånd med wait-for

wait-for --value avsöker tills ett elements värde matchar den förväntade strängen med samma smarta återställning som get-value (TextPattern → ValuePattern → SelectionPattern → Name). Returnerar slutkod 0 vid matchning, slutkod 1 vid timeout – vilket gör den till en CI-vänlig försäkran. Använd --property för att kontrollera en specifik UIA-egenskap i stället.

# 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

Bekräfta med JSON-utdata

Använd --json med PowerShell eller jq för mer komplexa kontroller:

Slutkodskontrakt för search och wait-for i --json läge: när inget element matchar (search) eller väntetiden överskrider tidsgränsen (wait-for), skriver kommandot ett fullständigt parsbart resultatkuvert till stdout ({ "matchCount": 0, ... } eller { "found": false, "timedOut": true, ... }) och returnerar slutkod 1. Stderr är tomt i --json läget (loggningsutdata ignoreras). Gren på kuvertfälten, eller på $LASTEXITCODE, beroende på vilken som är mer ergonomisk.

# 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)" }

Exempel på fullständigt röktest

# 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