Files
Boliang ZhangandCopilot 06e6ae43e2 feat(workspaces): add list and launch CLI (#51114)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Add Workspaces **list** and synchronous **launch** through a thin native
CLI and shared GUI/CLI execution core. Related to #49900;
capture/create/CRUD are excluded. Usage and contracts:
`doc\devdocs\modules\workspaces-cli.md`.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: N/A - partial scope of #49900.
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass (scoped local runs below;
CI/release gates remain)
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [x] **New binaries:** Added on the required places
- [x] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [x] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder - current integration:
`installer\PowerToysSetupVNext\CliShims.wxs`
- [x] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects - existing discovery; session-peer companion
signing updated
- [x] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- N/A: existing signing pipeline
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: N/A - follow-up not filed.

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

### Shared execution, conditional process boundary

```mermaid
flowchart TB
    EDITOR["Editor process<br/>C# / WPF"] -->|"start GUI Launcher"| ADAPTER
    SHELL["Terminal / script"] -->|"CLI shim starts CLI"| ADAPTER

    subgraph CALLER["Caller process: CLI.exe OR Launcher.exe in GUI mode"]
        ADAPTER["Thin entry adapter"]
        START["WorkspacesSession::Start<br/>snapshot + context check"]
        LOCAL["WorkspacesSession::Execute()<br/>function inside the caller process"]
        ADAPTER -->|"in-process"| START
        START -->|"verified Medium: in-process"| LOCAL
        LOCAL -.->|"typed return via Start"| ADAPTER
    end

    subgraph HOST["Elevated callers only: Medium host process<br/>PowerToys.WorkspacesLauncher.exe"]
        HANDOFF["Host entry<br/>receive and validate SessionHandoff"]
        REMOTE["WorkspacesSession::Execute()<br/>function inside this host process"]
        HANDOFF -->|"function call within the same process"| REMOTE
    end

    START -->|"elevated: create host<br/>read-only snapshot + restricted handles"| HANDOFF
    REMOTE -.->|"private anonymous result pipe"| START
    START -.->|"host outcome returned"| ADAPTER
    LOCAL <-->|"named pipes"| ARRANGER["WindowArranger process"]
    REMOTE <-->|"named pipes"| ARRANGER
    LOCAL <-->|"named pipes"| UI["Existing WPF Launcher UI process"]
    REMOTE <-->|"named pipes"| UI

    classDef shared fill:#dbeafe,stroke:#2563eb,color:#172554
    class START,LOCAL,REMOTE shared
```

The caller box represents **one of the two entry executables**, not both
in one process. Blue nodes are code statically linked from
`WorkspacesLib.lib`, not a DLL or shared service. **Medium GUI/CLI
callers execute in their own process without another Launcher host.**
Only elevated callers create a verified Medium host through the existing
`run_non_elevated` helper; it calls the same
`WorkspacesLib\LaunchExecution.cpp` core. No elevated fallback.

**`Execute()` is a function, not another EXE.** The host entry and its
`Execute()` share the same process ID. Execution uses a worker thread
inside that process, not another Launcher process. The two `Execute()`
nodes represent the same library implementation running in alternative
caller/host contexts.

- **Shared behavior:** one preparation, launch, arrangement,
confirmation and history flow. GUI retains progress; CLI shows only
required existing confirmation UI. GUI Cancel and console cancellation
use the shared stop/result path; already-started apps survive. Arranger
callbacks are stopped and joined before their helper owner is released.
An unresponsive inline Shell call yields `outcomeUnknown` before the
one-shot adapter exits, rather than killing a thread or claiming
cancellation succeeded.
- **Contracts:** `list` is read-only; summary JSON reuses existing
names. All arranged = `completed`/0; partial progress = `partial`/10; no
progress = `failed`/10. Incomplete, fractional or invalid final states
yield `outcomeUnknown`/9. Persistence verification failure retains exit
11 and displays application results in both text and JSON modes. The
existing `LaunchedAndMoved` enum and numeric IPC values are unchanged.
- **Persistence/integration:** preserve IDs, initialize missing legacy
IDs, update history best-effort; unsaved GUI drafts do not write saved
configuration/history. Only shim `bin` goes on PATH. Editor sibling-tool
resolution is executable-relative.
- **Telemetry:** one frontend `Workspaces_CLICommand` event when
optional diagnostics are enabled, following #50507's fixed command
category + success model. No workspace names/IDs, paths, arguments or
error text; the Medium host does not double-count. Uses the existing
native telemetry channel; documented in `DATA_AND_PRIVACY.md`.
- **Release IPC:** exact session-owner PID and official CLI/Launcher
identities remain checked. CI companion signing now includes CLI,
Launcher, arranger and Launcher UI; production signature checks are not
disabled.
- **Console isolation:** console workspace targets get their own
console; inline execution does not detach, redirect or share the CLI's
console.
- **Launch and Edit:** a missing temporary draft now falls back to the
saved workspace before GUID validation; malformed existing drafts still
fail. The existing UI regression explicitly checks that no draft is
present.
- **GUI file errors:** unreadable saved files and drafts show the
existing localized file-reading dialog with the correct source filename;
malformed-file dialogs also retain that context. Public CLI error JSON
is unchanged.
- **UI-test transport:** shared value setters place target options
before `--` and pass selectors/values literally. This fixes the
leading-dash command-line inputs rejected by CI's winapp 0.7.1 without
changing Workspaces test payloads or assertions.

### Changed-file breakdown

Full PR versus main, not just the latest commit. Each file is counted
once; test projects and fixtures are grouped under tests. These are file
categories, not process or library boundaries.

| Category | Files |
|---|---:|
| CLI adapter, output, resources and project | 7 |
| Shared session/execution entry, contracts, IPC, storage and telemetry
| 19 |
| Launcher engine/host adapter, arranger and UI | 18 |
| Managed storage and Editor path compatibility | 4 |
| Common helpers | 9 |
| Tests and fixtures | 24 |
| Build, installer and signing | 6 |
| Documentation and privacy catalog | 4 |
| **Total** | **91** |

The Launcher engine sources are compiled into `WorkspacesLib` even
though their source files remain under `WorkspacesLauncher`; the table
does not imply a separate engine process.

**Scope/known follow-ups:** general Editor save/conflict redesign and
the pre-existing localized-name/package-version matching bug are
deferred. Final GUI progress presentation still needs follow-up; this
update does not claim to fix its spinner-before-close behavior. The
native C++ parser is retained by the PR author's decision; a managed
System.CommandLine migration is not included. This does not amend the
repository-wide CLI convention.

<details>
<summary>List output and shared confirmation UI</summary>

![Workspaces CLI
list](https://github.com/user-attachments/assets/3755c810-0b85-4afe-b80f-f17f12e7f07d)
![Shared confirmation UI; controlled probe, no target
executed](https://github.com/user-attachments/assets/fbd09160-725d-47b7-907e-307bb2d749dc)

</details>

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

x64 Debug builds of the affected product and UI-test/fixture projects
passed; Release core, ModuleInterface, arranger, Launcher and CLI builds
also passed. The pre-GUI-error scoped native run passed **160 tests**.
Two deterministic paused-dispatch regressions reproduced `0xC0000005`
before the teardown fix (snapshot and final-result callbacks); both now
return acknowledged cancellation. Test hooks are compiled only into the
fixture, not production builds. **48 signing-selection** tests passed
earlier against unchanged selection logic. The preceding missing-draft
fix passed **39 focused tests** plus the complete local-host `winapp`
Launch and Edit flow, with settings/pointer/Editor state restored. This
is targeted host validation, not full local OS-matrix sign-off.

The GUI error follow-up `8ea5619586` passed **33 focused native tests in
each of Debug and Release**, including a regression that failed before
the fix. Both real saved-file/draft error dialogs were driven locally
with UIA; original configuration bytes and draft absence were restored.

The CI transport follow-up `e0945376e6` passed **19 focused
shared-harness tests in each of Debug and Release**. Using the
hash-verified winapp **0.7.1** archive from the failing CI revision, the
original invocation reproduced `invalid_arguments`; the fixed wrappers
passed **nine owned-UI setter checks** for leading options, quoted text,
empty text, and negative numeric values. The TextBox, editable ComboBox,
NumberBox, and Slider setters share the corrected argument boundary.
This is focused wrapper validation, not a claim that the full Workspaces
suite ran locally.

<details>
<summary>Commands and results</summary>

Used the verified side-by-side SDK 10.0.303; no global/repository SDK or
package-source change. With `$root='D:\PowerToys-workspace-cli'`, from
each affected project directory:

```powershell
& "$root\tools\build\build.ps1" -Platform x64 -Configuration Debug -ExtraArgs @("/p:SolutionDir=$root\", '/p:BuildProjectReferences=false', '/p:WorkspacesCliLiveTests=true')
# Passed, exit 0.
& "$root\tools\build\build.ps1" -Platform x64 -Configuration Release -ExtraArgs @("/p:SolutionDir=$root\", '/p:BuildProjectReferences=false')
# Passed, exit 0, for core/arranger/Launcher/CLI.
```

Missing Release UI dependencies were first built with project references
enabled:

```powershell
# From src\modules\Workspaces\WorkspacesLauncherUI:
& "$root\tools\build\build.ps1" -Platform x64 -Configuration Release -ExtraArgs @("/p:SolutionDir=$root\")
# Passed, exit 0.
```

Pre-GUI-error scoped native run (`$evidence` is the local report
directory):

```powershell
$env:WORKSPACES_CLI_LIVE_TESTS='1'
& 'C:\Program Files\Microsoft Visual Studio\18\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe' "$root\x64\Debug\tests\Workspaces\Workspaces.Lib.UnitTests.dll" '/TestCaseFilter:FullyQualifiedName~CliContractTests|FullyQualifiedName~CliJsonOutputTests|FullyQualifiedName~CliRuntimeTests|FullyQualifiedName~CliHandoffTests|FullyQualifiedName~CliWorkerTests|FullyQualifiedName~WorkspaceStoreTests|FullyQualifiedName~SignatureVerificationTests|FullyQualifiedName~SignatureTrustTests|FullyQualifiedName~ExecutableTargetTests|FullyQualifiedName~ElevatedLaunchGateTests|FullyQualifiedName~PendingLaunchApprovalTests' "/ResultsDirectory:$evidence" '/Logger:trx;LogFileName=teardown-race-green.trx' '/Logger:console;verbosity=minimal'
# Passed: 160; failed/skipped: 0; exit 0.
& 'C:\Program Files\Microsoft Visual Studio\18\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe' "$root\x64\Debug\tests\Workspaces\Workspaces.Lib.UnitTests.dll" '/TestCaseFilter:FullyQualifiedName~CliContractTests|FullyQualifiedName~JsonUtilsTests' "/ResultsDirectory:$evidence" '/Logger:trx;LogFileName=missing-draft-headless.trx' '/Logger:console;verbosity=minimal'
# Passed after the draft fix: 39; failed/skipped: 0; exit 0.
Invoke-Pester -Script 'D:\PowerToys-workspace-cli\.pipelines\tests\uiTestSigningSelection.Tests.ps1' -PassThru
# Passed: 48; failed: 0.
git diff --check
# Passed, exit 0.
```

Telemetry lifecycle tests use a recording sink and synthetic commands;
they neither transmit telemetry nor change diagnostic consent.

Recorded host UI actions (3892 was this run's owned Editor PID, not a
reusable PID):

```powershell
winapp ui 'invoke' 'EditButton' '-a' '3892' '--json'
winapp ui 'invoke' 'LaunchEditButton' '-a' '3892' '--json'
winapp ui 'invoke' 'SnapshotButton' '-a' '3892' '--json'
winapp ui 'invoke' 'SaveButton' '-a' '3892' '--json'
# All passed, exit 0; fixture startup, exact placement, recapture and persisted IDs were asserted.
```

</details>

Latest shared-harness build/test commands, from
`src\common\UITestAutomation.Next.UnitTests`:

```powershell
& "$root\tools\build\build.ps1" -Platform x64 -Configuration Debug -ExtraArgs @("/p:SolutionDir=$root\")
& "$root\tools\build\build.ps1" -Platform x64 -Configuration Release -ExtraArgs @("/p:SolutionDir=$root\")
# Both passed, exit 0, including analyzers.
& "$root\x64\Debug\tests\UITestAutomation.Next.UnitTests\net10.0-windows10.0.26100.0\UITestAutomation.Next.UnitTests.exe" --filter 'FullyQualifiedName~WinappCliTests|FullyQualifiedName~SessionTests' --report-trx --report-trx-filename ci-set-value-unit.trx --results-directory $evidence
& "$root\x64\Release\tests\UITestAutomation.Next.UnitTests\net10.0-windows10.0.26100.0\UITestAutomation.Next.UnitTests.exe" --filter 'FullyQualifiedName~WinappCliTests|FullyQualifiedName~SessionTests' --report-trx --report-trx-filename ci-set-value-unit-release.trx --results-directory $evidence
# Each passed: 19; failed/skipped: 0; exit 0.
```

**CI status:**
[391837](https://dev.azure.com/shine-oss/62769a65-d989-45e3-803c-9ad21fcf2ea2/_build/results?buildId=391837)
**succeeded** on current head `e0945376e6`, tested as merge `e27f537028`
with main `79ceeee01c`. SDK/x64/ARM64 builds passed, and **34/34
Workspaces UI tests passed on each of Windows 10 x64, Windows 11 x64,
and Windows 11 ARM64**, with zero failures or skips. Finished 2026-10-26
16:18:46 UTC.

The preceding
[391820](https://dev.azure.com/shine-oss/62769a65-d989-45e3-803c-9ad21fcf2ea2/_build/results?buildId=391820)
on `8ea5619586` passed product builds but had 29/34 UI tests pass on
each platform. All five failures were leading-dash textbox values
rejected by winapp 0.7.1; the shared helper was identical to main and
predates this PR. The setter fix resolves those failures without
changing Workspaces product code or weakening assertions. Fresh
High-parent/UAC, installer servicing and broader mixed-DPI validation
remain release gates.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 664ee900-ce2d-4112-ac57-395314d818dc
2026-10-27 11:29:49 +08:00
..

PowerToys Modules

This section contains documentation for individual PowerToys modules, including their architecture, implementation details, and debugging tools.

Available Modules

Module Description
Advanced Paste Tool for enhanced clipboard pasting with formatting options
Always on Top Tool for pinning windows to stay on top of other windows
Awake Tool to keep your computer awake without modifying power settings
Color Picker Tool for selecting and managing colors from the screen
Command Not Found Tool suggesting package installations for missing commands
Crop and Lock Tool for cropping application windows into smaller windows or thumbnails
Environment Variables Tool for managing user and system environment variables
FancyZones (debugging tools) Window manager utility for custom window layouts
File Explorer add-ons Extensions for enhancing Windows File Explorer functionality
File Locksmith Tool for finding processes that lock files
Hosts File Editor Tool for managing the system hosts file
Image Resizer Tool for quickly resizing images within File Explorer
Keyboard Manager Tool for remapping keys and keyboard shortcuts
Mouse Utilities Collection of tools to enhance mouse and cursor functionality
Mouse Without Borders Tool for controlling multiple computers with a single mouse and keyboard
NewPlus Context menu extension for creating new files in File Explorer
Peek File preview utility for quick file content viewing
Power Rename Bulk file renaming tool with search and replace functionality
PowerToys Run (deprecation soon) Quick application launcher and search utility
Quick Accent Tool for quickly inserting accented characters and special symbols
Registry Preview Tool for visualizing and editing Registry files
Screen Ruler Tool for measuring pixel distances and color boundaries on screen
Shortcut Guide Tool for displaying Windows keyboard shortcuts when holding the Windows key
Text Extractor Tool for extracting text from images and screenshots
Window Hopper (Alt Window Cycle) Tool for cycling between windows of the focused application
Workspaces Tool for saving and restoring window layouts for different projects
ZoomIt Screen zoom and annotation tool

Adding New Module Documentation

When adding documentation for a new module:

  1. Create a dedicated markdown file for the module (e.g., modulename.md)
  2. If the module has specialized debugging tools, consider creating a separate tools document (e.g., modulename-tools.md)
  3. Update this index with links to the new documentation
  4. Follow the existing documentation structure for consistency