## Summary Moves the MSIX sparse package's `ExternalLocation` from the PowerToys root install folder to the `WinUI3Apps\` subfolder, isolating DACL contamination from preview handler DLLs. ## Problem On Windows 23H2/24H2/25H2, MSIX sparse package registration adds AppContainer SIDs (`S-1-15-2-*` / `S-1-15-3-*`) to the DACL of the `ExternalLocation` folder. Since `ExternalLocation` pointed to the PowerToys root install folder, this broke File Explorer preview handlers — `prevhost.exe` (running at LOW integrity) could no longer load preview handler DLLs (`.txt`, `.md`, `.pdf`, `.svg`, etc.). ## Fix - **`CustomAction.cpp`**: Changed `ExternalLocation` from `installFolderPath` → `installFolderPath + L"WinUI3Apps\\"` - **`AppxManifest.xml`**: Removed unused PowerOCR `<Application>` entry; stripped `WinUI3Apps\` prefix from `Executable` paths (now relative to new ExternalLocation) - **`CmdPal.Ext.PowerToys.csproj`**: Moved `OutputPath` to `WinUI3Apps\` so the AOT-compiled extension EXE resolves correctly under the new ExternalLocation - **WiX installer files**: Updated source/install paths for KBM assets, CmdPal satellite assemblies, and `CommandPalette.Extensions.winmd` that moved with the CmdPal output - **ESRP signing**: Updated CmdPal dll/exe paths to include `WinUI3Apps\` prefix ## Validation | Test | 25H2 | 23H2 | |------|------|------| | DACL isolation (no S-1-15-* on root) | ✅ | ✅ | | Preview handlers (.txt, .md, .pdf, .svg) | ✅ | ✅ | | Peek | ✅ | ✅ | | Context menus (PowerRename, FileLocksmith, ImageResizer, New+) | ✅ | ✅ | | Upgrade path (old → new) | ✅ | ✅ | ## Files changed (12) - `installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp` — core fix - `src/PackageIdentity/AppxManifest.xml` — manifest cleanup - `src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Microsoft.CmdPal.Ext.PowerToys.csproj` — output path - `src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/PowerToysResourcesHelper.cs` — icon path - `installer/PowerToysSetupVNext/BaseApplications.wxs` — winmd source path - `installer/PowerToysSetupVNext/KeyboardManager.wxs` — KBM assets path - `installer/PowerToysSetupVNext/Resources.wxs` — CmdPal satellite paths - `installer/PowerToysSetupVNext/generateAllFileComponents.ps1` — scan path - `.pipelines/ESRPSigning_core.json` — signing paths - `src/PackageIdentity/BuildSparsePackage.ps1` — dev script hint - `src/PackageIdentity/readme.md` — docs - `doc/devdocs/modules/cmdpal/powertoys-extension-local-development.md` — docs --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2.8 KiB
Local PowerToys Extension Development
This guide is for iterating on src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Microsoft.CmdPal.Ext.PowerToys.csproj.
The extension is registered through the shared sparse package defined in src/PackageIdentity/AppxManifest.xml. That manifest declares Microsoft.CmdPal.Ext.PowerToys.exe relative to the sparse package's ExternalLocation (WinUI3Apps\ subfolder), so the sparse package and the extension must be built for the same platform and configuration, for example x64\Debug.
Local development loop
-
Build
src/PackageIdentity/PackageIdentity.vcxproj.This creates
PowerToysSparse.msixin the repo output root for the selected platform and configuration, and prints theAdd-AppxPackagecommand you should run next. -
Trust the development certificate before running
Add-AppxPackage.The
PackageIdentitybuild creates or reusessrc/PackageIdentity/.user/PowerToysSparse.certificate.sample.cer.Import it into
CurrentUser\TrustedPeople:$repoRoot = "C:/git/PowerToys" Import-Certificate -FilePath "$repoRoot/src/PackageIdentity/.user/PowerToysSparse.certificate.sample.cer" -CertStoreLocation Cert:\CurrentUser\TrustedPeopleIf Windows still reports a trust failure such as
0x800B0109, also import the same certificate intoCert:\CurrentUser\TrustedRoot. -
Run the
Add-AppxPackagecommand printed by thePackageIdentitybuild.That registers
Microsoft.PowerToys.SparseAppas a sparse package and points it at the matching output root through-ExternalLocation.The command will look like this:
Add-AppxPackage -Path "<repo>\<Platform>\<Configuration>\PowerToysSparse.msix" -ExternalLocation "<repo>\<Platform>\<Configuration>\WinUI3Apps" -
Build
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Microsoft.CmdPal.Ext.PowerToys.csprojin the same platform and configuration.This project writes
Microsoft.CmdPal.Ext.PowerToys.exeinto theWinUI3Apps\subfolder of the output root, such asx64\Debug\WinUI3AppsorARM64\Debug\WinUI3Apps. That matches theExecutable="Microsoft.CmdPal.Ext.PowerToys.exe"entry insrc/PackageIdentity/AppxManifest.xmlresolved relative to the sparse package's ExternalLocation. -
Restart Command Palette.
Close any running CmdPal instance and launch it again so it reloads app extensions and picks up the rebuilt
Microsoft.CmdPal.Ext.PowerToysbinaries.
When to repeat each step
- Rebuild and re-register
PackageIdentitywhen the sparse package manifest changes, the signing certificate changes, or you switch to a different output root such asARM64\Debug. - For normal code changes in
Microsoft.CmdPal.Ext.PowerToys, rebuilding the extension project and restarting CmdPal is enough.