From 68ed78cd4643aaf1fc3f0abcdeb66fa7f8112860 Mon Sep 17 00:00:00 2001 From: Jessica Dene Earley-Cha <12740421+chatasweetie@users.noreply.github.com> Date: Tue, 14 Oct 2025 10:20:33 -0700 Subject: [PATCH 01/13] microsoft store and winget instructions publishing content --- .../command-palette/publish-extension.md | 427 ++++++++++++++++-- 1 file changed, 399 insertions(+), 28 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index 72e3671043..b6a832fed1 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -1,35 +1,183 @@ --- -title: Command Palette Extension Publishing -description: The Command Palette provides a full extension model, allowing you to create custom experiences for the palette. Find info about how to publish an extension. -ms.date: 2/28/2025 -ms.topic: concept-article +title: Publish Command Palette extensions +description: Learn how to publish Command Palette extensions to Microsoft Store and WinGet to share your custom experiences with users. +ms.date: 02/28/2025 +ms.topic: how-to no-loc: [PowerToys, Windows, Insider] # Customer intent: As a Windows developer, I want to learn how to publish an extension for the Command Palette. --- -# Publishing your extension +# Publish Command Palette extensions -The Command Palette provides a full extension model, allowing developers to create their own experiences for the palette. This document provides information about how to publish an extension. +This article provides instructions for Command Palette extensions that were created using the Command Palette template. -There is a "Sample Project" template included with the Command Palette. This can be used to quickly generate a project that creates a new extension. This will include the `.sln`, `.csproj`, and `.appxmanifest` files needed to create a new extension, as well as the plumbing to get it ready to be published. You will then open the project to the `{ExtensionName}CommandsProvider` class (where `{ExtensionName}` is replaced with the name of your extension project) and implement your commands. +You can publish your Command Palette extension through the Microsoft Store, WinGet, or both. This article includes instructions for preparing and publishing your extension to both distribution platforms. -## Pre-requisites +## Microsoft Store + +Command Palette extensions can be published to the Microsoft Store. The publishing process is similar to other apps or extensions. You create a new submission in Partner Center and upload your `.msix` package. Command Palette automatically discovers your extension when users install it from the Microsoft Store. + +> [!NOTE] +> **MSIX packages explained** +> MSIX is Microsoft's modern app packaging format that provides secure installation, automatic updates, and clean uninstallation. It replaces older formats like MSI and ensures your extension integrates properly with Windows security and deployment features. + +Command Palette can't search for or install extensions that are only listed in the store. You can find those extensions by running the following command: + +```cmd +ms-windows-store://assoc/?Tags=AppExtension-com.microsoft.commandpalette +``` + +You can run this command from the "Run commands" command in Command Palette, from the command line, or from the Run dialog. + +## Guide to Microsoft Store publishing + +> [!NOTE] +> This guide provides basic Microsoft Store publishing steps specific to Command Palette extensions. For comprehensive Microsoft Store publishing guidance, including detailed submission requirements, certification processes, and best practices, see [Publish Windows apps and games](https://learn.microsoft.com/windows/apps/publish/). + +### Prerequisites + +> [!IMPORTANT] +> **What is Partner Center?** +> Partner Center is Microsoft's portal for app developers to manage Microsoft Store submissions, track analytics, and handle app certification. + +- [Register as a Windows app developer in Partner Center](https://learn.microsoft.com/en-us/windows/apps/publish/partner-center/partner-center-developer-account) +- Create all required app icons and ensure they're properly sized ([Create icons using Visual Studio's asset generation tool](https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/visual-studio-asset-generation)) + +### Set up Microsoft Store + +1. Navigate to the [Microsoft Partner Center](https://partner.microsoft.com/dashboard/home). +1. Under **Workspaces**, select **Apps and games**. +1. Select **+ New Product**. +1. Select **MSIX or PWA app**. +1. Create a name or reserve a product name. +1. Start the submission and complete as much as you can until you reach the **Packages** section. +1. In the left navigation, under **Product Management**, select **Product identity**. +1. Note the `Package/Identity/Name`, `Package/Identity/Publisher`, and `Package/Properties/PublisherDisplayName` for the following steps. + +### Prepare the extension + +1. In your IDE, open `\Package.appxmanifest`. +1. Update the publisher and publisher display name: + +```xml + + Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" + Version="0.0.1.0" /> + + + TemplateDisplayName + A Lone Developer + Assets\StoreLogo.png + +``` + +1. In your IDE, open `.csproj`. +1. Locate the `PropertyGroup` element and add the following properties: + +```xml + Package/Identity/Name + CN=########-####-####-####-############ + 0.0.1.0 +``` + +### Build MSIX -The following tools are required to build and publish your extension: +1. In the terminal, change to the `\` directory. +1. Create an x64 build MSIX with the following command: -- [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) (Community, Professional, or Enterprise edition) + ```powershell + dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=x64 + ``` + +1. Create an ARM64 build MSIX with the following command: + + ```powershell + dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=ARM64 + ``` + +1. Locate the MSIX files: + + ```powershell + cd ; dir bin -Recurse -Filter "*.msix" + ``` + +1. Note the locations of the `__x64.msix` and `__arm64.msix` files. + +1. Create a new `bundle_mapping.txt` file and include the following content, updating the paths to your MSIX files: + + ```text + [Files] + "bin\x64\Release\PATH\__x64.msix" "__x64.msix" + "bin\ARM64\Release\PATH\__arm64.msix" "__arm64.msix" + ``` + +1. Create a bundle that combines both architectures into a single package for Microsoft Store submission. Update the `` and ``: + + ```powershell + makeappx bundle /v /d bin\Release\ /p __Bundle.msixbundle + ``` + + > [!NOTE] + > If `makeappx` isn't recognized, check which version of Windows SDK you have installed: + > + > ```powershell + > Get-ChildItem "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v*" | Select-Object PSChildName + > ``` + > + > Then update the following script with the version number: + > + > ```powershell + > & "C:\Program Files (x86)\Windows Kits\\bin\[version]\x64\makeappx.exe" bundle /f bundle_mapping.txt /p __Bundle.msixbundle + > ``` + +1. Locate the bundle: + + ```powershell + ls *.msixbundle + ``` + +1. You should find the file: `__Bundle.msixbundle`. + +#### MSIX build validation + +Verify your MSIX build is ready by checking: + +- ✅ You've updated `Package.appxmanifest` with correct Identity and Properties +- ✅ You've updated `.csproj` with AppxPackage properties +- ✅ Both x64 and ARM64 MSIX files were built successfully +- ✅ The `bundle_mapping.txt` file contains correct paths to both MSIX files +- ✅ The `.msixbundle` file was created without errors +- ✅ You can locate the final bundle file + +If any items are missing or failed, review the build commands and check for error messages before continuing. + + +### Microsoft Store submission + +1. Navigate to the [Microsoft Partner Center](https://partner.microsoft.com/dashboard/home) and open your newly created extension project. +1. In **Packages**, upload the created MSIX bundle. +1. Complete the rest of the submission. The following suggestions can help you: + 1. In **Languages supported in packages**, under your supported language (for example, English (United States)), in **Description**, make sure to include ` integrates with the Windows Command Palette to...` + 1. **Tip**: Add additional testing information. + - In the left navigation, locate **Supplemental info** and select **Additional Testing Information**. Here's an [example](https://github.com/chatasweetie/CmdPalExtensions/blob/main/microsoftStoreResources/TesterInstructions.txt). +1. Submit your extension to the store. + +After submission, Microsoft will review your extension for certification. Monitor your submission status in Partner Center and check for email notifications about approval. Once approved, your extension will be available in the Microsoft Store within a few hours. ## WinGet -Publishing packages to WinGet is the recommended way to share your extensions with users. Extension packages which are listed on WinGet can be discovered and installed directly from the Command Palette. +> [!TIP] +> **What is WinGet?** +> WinGet is Microsoft's open-source command-line package manager for Windows. It's similar to package managers like npm or pip, but for Windows applications. Publishing to WinGet allows users to install your extension with a simple `winget install` command and enables automatic discovery within Command Palette. -For the most part, following the steps on [Submit packages to Windows Package Manager](../../package-manager/package/manifest.md) will get your extension onto WinGet itself. +Publishing packages to WinGet is the recommended way to share your extensions with users. Extension packages that are listed on WinGet can be discovered and installed directly from Command Palette. -Before submitting your manifest to WinGet, you'll need to check two things: +Before submitting your manifest to WinGet, check the following two requirements: -### Add `windows-commandpalette-extension` tag +### Add the `windows-commandpalette-extension` tag -Command Palette uses the special `windows-commandpalette-extension` tag to discover extensions. Make sure that your manifest includes this tag, so that Command Palette can discover your extension. Add the following to each `.locale.*.yaml` file in your manifest: +Command Palette uses the special `windows-commandpalette-extension` tag to discover extensions. Make sure that your manifest includes this tag so that Command Palette can discover your extension. Add the following code to each `.locale.*.yaml` file in your manifest: ```yaml Tags: @@ -38,35 +186,258 @@ Tags: ### Ensure WindowsAppSdk is listed as a dependency -If you're using Windows App SDK, then you'll need to make sure that it is listed as a dependency of your package. Add the following to your `.installer.yaml` manifest: +If you're using Windows App SDK, make sure that it's listed as a dependency of your package. Add the following code to your `.installer.yaml` manifest: ```yaml Dependencies: PackageDependencies: - - PackageIdentifier: Microsoft.WindowsAppRuntime.1.6 + - PackageIdentifier: Microsoft.WindowsAppRuntime.#.# ``` -If you're not using the template project, then this may not apply to you. +## Guide to WinGet publishing - +1. In `.csproj`, from the ``: + - Remove `win-$(Platform).pubxml` + - Add `None` +1. `cd` into `CmdPalRandomRiddleExtension\CmdPalRandomRiddleExtension\Properties\` -## Microsoft Store -Command Palette extensions can be published to the Microsoft Store. The process is similar to publishing other apps or extensions. You create a new submission in the Partner Center and upload your `.msix` package. The Command Palette automatically discovers your extension when it's installed from the Microsoft Store. +1. `cd` into the directory that contains your `.cs` +1. Locate `CLSID` + 1. Open the extension's main `.cs` file (for example, `.cs`). + 1. Look for the `[Guid("...")]` attribute above the class declaration. + 1. This GUID is your CLSID - copy it exactly as shown. -Command Palette cannot, however, search for & install extensions that are only listed in the store. You can find those by running the following command: + ```csharp + // Example from .cs + [Guid("0ab5d8ab-b206-4023-99f0-97dde26e14f2")] // This is the CLSID + public sealed partial class : IExtension + ``` -```cmd -ms-windows-store://assoc/?Tags=AppExtension-com.microsoft.commandpalette + > [!NOTE] + > **What is a CLSID?** + > A CLSID (Class Identifier) is a unique identifier that Windows uses to identify COM (Component Object Model) components. Each Command Palette extension needs a unique CLSID so Windows can properly register and load your extension. This GUID is automatically generated when you create your extension project. + +1. Create a `build-exe.ps1` file, for a simple extension you can copy and customize the following: + +**Template: `build-exe.ps1`** +```powershell +# Replace with actual extension name (e.g., CmdPalCatFunExtension) +# Replace with version number (e.g., 0.0.1.0) +param( + [string]$Configuration = "Release", + [string]$Version = "", # Update version + [string]$Platform = "x64" +) + +# Build and publish self-contained EXE +$ProjectDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$ProjectPath = ".csproj" # Replace with actual .csproj name + +# Clean previous builds +Write-Host "Cleaning previous builds..." -ForegroundColor Yellow +if (Test-Path "$ProjectDir\bin") { + Remove-Item -Path "$ProjectDir\bin" -Recurse -Force -ErrorAction SilentlyContinue +} +if (Test-Path "$ProjectDir\obj") { + Remove-Item -Path "$ProjectDir\obj" -Recurse -Force -ErrorAction SilentlyContinue +} + +# Restore packages +Write-Host "Restoring NuGet packages..." -ForegroundColor Yellow +dotnet restore $ProjectFile + +# Build and publish +Write-Host "Building and publishing application..." -ForegroundColor Yellow +dotnet publish $ProjectFile ` + --configuration $Configuration ` + --runtime "win-$Platform" ` + --self-contained true ` + --output "$ProjectDir\bin\$Configuration\win-$Platform\publish" + +if ($LASTEXITCODE -ne 0) { + throw "Build failed with exit code: $LASTEXITCODE" +} + +# Check if files were published +$publishDir = "$ProjectDir\bin\$Configuration\win-$Platform\publish" +$fileCount = (Get-ChildItem -Path $publishDir -Recurse -File).Count +Write-Host "✅ Published $fileCount files to $publishDir" -ForegroundColor Green + +# Update version in setup.iss +Write-Host "Updating installer script version..." -ForegroundColor Yellow +$setupTemplate = Get-Content "$ProjectDir\setup-template.iss" -Raw +$setupScript = $setupTemplate -replace '#define AppVersion ".*"', "#define AppVersion `"$Version`"" +$setupScript | Out-File -FilePath "$ProjectDir\setup.iss" -Encoding UTF8 + +# Create installer with Inno Setup +Write-Host "Creating installer with Inno Setup..." -ForegroundColor Yellow +$InnoSetupPath = "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" +if (-not (Test-Path $InnoSetupPath)) { + $InnoSetupPath = "${env:ProgramFiles}\Inno Setup 6\iscc.exe" +} + +if (Test-Path $InnoSetupPath) { + & $InnoSetupPath "$ProjectDir\setup.iss" + + if ($LASTEXITCODE -eq 0) { + $installer = Get-ChildItem "$ProjectDir\bin\$Configuration\installer\*.exe" | Select-Object -First 1 + if ($installer) { + $sizeMB = [math]::Round($installer.Length / 1MB, 2) + Write-Host "✅ Created installer: $($installer.Name) ($sizeMB MB)" -ForegroundColor Green + } + } else { + throw "Inno Setup failed with exit code: $LASTEXITCODE" + } +} else { + Write-Warning "Inno Setup not found at expected locations" +} + +Write-Host "🎉 Build completed successfully!" -ForegroundColor Green +``` + +1. Create a `setup-template.iss` file, for a simple extension you can copy and customize the following: + +**Template: `setup-template.iss`** +```ini +; Replace with unique GUID +; Replace with actual extension name +; Replace with your name +; Replace with actual extension name + +[Setup] +AppId={{}} ; Replace +AppName= ; Replace +AppVersion={#AppVersion} +AppPublisher= ; Replace +DefaultDirName={autopf}\ ; Replace +OutputDir=bin\Release\installer +OutputBaseFilename=-Setup-{#AppVersion} ; Replace +Compression=lzma +SolidCompression=yes +MinVersion=10.0.19041 + + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Files] +Source: "bin\Release\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs + +[Icons] +Name: "{group}\"; Filename: "{app}\.exe" + +[Registry] +Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{}}"; ValueData: "" ; Replace , note: do not replace SOFTWARE\Classes\CLSID\ portion +Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{}}\LocalServer32"; ValueData: "{app}\.exe -RegisterProcessAsComServer" ; Replace , note: do not replace SOFTWARE\Classes\CLSID\ portion + +``` + +Note: you can test this locally by having .NET 9 `dotnet` and Inno Setup (todo add links) + +```powershell +# verify .Net 9 is installed +dotnet --version + +# verify Inno Setup is installed +Test-Path "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" + +# build installer, this will take a while +.\build-exe.ps1 -Version "0.0.1.0" + +# verify that -Setup-0.0.1.0.exe is listed +Get-ChildItem "bin\Release\installer\" -File +``` + +TODO: Explain Github Actions briefly + +1. `cd ..` up a directory, you should be in the directory that contains `.sln` +1. create a new repo: + +```powershell +mkdir .github/workflows ``` -You can run this from the "Run commands" command in Command Palette, or from the command-line, or from the Run dialog. +1. In the `workflows` directory, create a new file called `release-extension.yml`. +1. Copy the contents of [release-extension-template.yml](https://github.com/chatasweetie/CmdPalExtensions/blob/main/.github/workflows/release-extension-template.yml) to your local file. This file is a Github Action scrip that does the following: + + - Setup (.NET, Inno Setup) + - Get Version (simple version detection) + - Build App (straightforward dotnet publish) + - Create Installer (simple Inno Setup call) + - Upload Results (clear artifact + release steps) +1. Update the placeholders in `release-extension.yml`: + - DEVELOPER_NAME + - GITHUB_REPO_URL + - EXTENSION_NAME + - DISPLAY_NAME + - FOLDER_NAME + - GENERATE-NEW-GUID-HERE +1. git commit the 3 new files: `build-exe.ps1`, `setup.iss`,`release-extension.yml` +1. Push changes to Github. +1. Trigger the GitHub Action: + + ```powershell + gh workflow run release-extension.yml --ref main -f create_release=true -f "release_notes= **First Release of Extension for Command Palette** + The inaugural release of the for Command Palette..." + ``` + +### WinGet submission + +> [!IMPORTANT] +> The first submission must be manual. A GitHub Action template will be linked at the end for post-first submission updates. + +**Why manual first?** + +- `wingetcreate new` requires interactive input for package details +- GitHub Actions can't provide interactive console input + +#### Manual first submission + +1. Activate interactive wingetcreate: + + ```powershell + # Use your actual GitHub release URL (example with version 0.0.1 for first release) + wingetcreate new "https://github.com///releases/download/-v0.0.1/-Setup-0.0.1.exe" + ``` + Note: FOr the Github Release URL, you can go to the release page, under **Assets** you can right click the .exe file and + +1. When `wingetcreate` prompts you, press **Enter** if the suggested response is pulled from the EXE file, for example: `PackageIdentifier`, `PackageVersion`, `Publisher`, etc. + - **For optional modification questions**, answer **No**: + - "Would you like to modify the optional default locale fields?" → **No** + - "Would you like to modify the optional installer fields?" → **No** + - "Would you like to make changes to this manifest?" → **No** + - **Final submission question**: + - "Would you like to submit your manifest to the Windows Package Manager repository?" → **Yes** + +After answering "Yes" to submit: + +- `wingetcreate` forks the microsoft/winget-pkgs repository to your GitHub account +- Creates a new branch with your package manifests +- Opens a pull request automatically +- Provides the PR URL for tracking + +After submitting your pull request, the WinGet team will review your manifest for compliance and accuracy. You can monitor the PR status on GitHub and respond to any feedback from reviewers. Once approved and merged, your extension will be available through WinGet within a few hours. + +#### WinGet updates via GitHub Actions + +You can use GitHub Actions to update your already submitted projects to WinGet. + +Check out how [PowerToys](https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml) does this. ## Related content From 9ef2a58c0d1cc26cab576d30201ed9f55744759a Mon Sep 17 00:00:00 2001 From: Jessica Dene Earley-Cha <12740421+chatasweetie@users.noreply.github.com> Date: Tue, 14 Oct 2025 11:08:19 -0700 Subject: [PATCH 02/13] update scripts --- .../command-palette/publish-extension.md | 202 ++++++++++++++---- 1 file changed, 166 insertions(+), 36 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index b6a832fed1..de65af077c 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -208,6 +208,10 @@ Dependencies: wingetcreate --version ``` +### Prepare Github Repo + +TODO: add instructions on adding secreats + ### Prepare the project 1. In `.csproj`, from the ``: @@ -217,36 +221,32 @@ Dependencies: 1. `cd` into the directory that contains your `.cs` -1. Locate `CLSID` - 1. Open the extension's main `.cs` file (for example, `.cs`). - 1. Look for the `[Guid("...")]` attribute above the class declaration. - 1. This GUID is your CLSID - copy it exactly as shown. - - ```csharp - // Example from .cs - [Guid("0ab5d8ab-b206-4023-99f0-97dde26e14f2")] // This is the CLSID - public sealed partial class : IExtension - ``` - - > [!NOTE] - > **What is a CLSID?** - > A CLSID (Class Identifier) is a unique identifier that Windows uses to identify COM (Component Object Model) components. Each Command Palette extension needs a unique CLSID so Windows can properly register and load your extension. This GUID is automatically generated when you create your extension project. - 1. Create a `build-exe.ps1` file, for a simple extension you can copy and customize the following: **Template: `build-exe.ps1`** ```powershell -# Replace with actual extension name (e.g., CmdPalCatFunExtension) -# Replace with version number (e.g., 0.0.1.0) +# TEMPLATE: PowerShell Build Script for Command Palette Extensions +# +# To use this template for a new extension: +# 1. Copy this file to your extension's project folder as "build-exe.ps1" +# 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +# 2. Replace with your extension version (e.g., 0.0.1.0) +# 3. Update the default version to match your project file's AppxPackageVersion +# 4. Ensure you have a setup-template.iss file in the same directory + param( [string]$Configuration = "Release", - [string]$Version = "", # Update version + [string]$Version = "", # UPDATE: Change this to match your project's default version [string]$Platform = "x64" ) -# Build and publish self-contained EXE +$ErrorActionPreference = "Stop" + +Write-Host "Building EXTENSION_NAME EXE installer..." -ForegroundColor Green +Write-Host "Version: $Version" -ForegroundColor Yellow + $ProjectDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$ProjectPath = ".csproj" # Replace with actual .csproj name +$ProjectFile = "$ProjectDir\EXTENSION_NAME.csproj" # Clean previous builds Write-Host "Cleaning previous builds..." -ForegroundColor Yellow @@ -310,28 +310,49 @@ if (Test-Path $InnoSetupPath) { Write-Host "🎉 Build completed successfully!" -ForegroundColor Green ``` +1. Locate `CLSID` + 1. Open the extension's main `.cs` file (for example, `.cs`). + 1. Look for the `[Guid("...")]` attribute above the class declaration. + 1. This GUID is your CLSID - copy it exactly as shown. + + ```csharp + // Example from .cs + [Guid("0ab5d8ab-b206-4023-99f0-97dde26e14f2")] // This is the CLSID + public sealed partial class : IExtension + ``` + + > [!NOTE] + > **What is a CLSID?** + > A CLSID (Class Identifier) is a unique identifier that Windows uses to identify COM (Component Object Model) components. Each Command Palette extension needs a unique CLSID so Windows can properly register and load your extension. This GUID is automatically generated when you create your extension project. + 1. Create a `setup-template.iss` file, for a simple extension you can copy and customize the following: **Template: `setup-template.iss`** ```ini -; Replace with unique GUID -; Replace with actual extension name -; Replace with your name -; Replace with actual extension name +; TEMPLATE: Inno Setup Script for Command Palette Extensions +; +; To use this template for a new extension: +; 1. Copy this file to your extension's project folder as "setup-template.iss" +; 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +; 3. Replace DISPLAY_NAME with your extension's display name (e.g., My Extension) +; 4. Replace DEVELOPER_NAME with your name (e.g., Your Name Here) +; 5. Replace CLSID-HERE with a new CLSID for COM registration +; 6. Update the default version to match your project file + +#define AppVersion "0.0.1.0" [Setup] -AppId={{}} ; Replace -AppName= ; Replace +AppId={{GUID-HERE}} +AppName=DISPLAY_NAME AppVersion={#AppVersion} -AppPublisher= ; Replace -DefaultDirName={autopf}\ ; Replace +AppPublisher=DEVELOPER_NAME +DefaultDirName={autopf}\EXTENSION_NAME OutputDir=bin\Release\installer -OutputBaseFilename=-Setup-{#AppVersion} ; Replace +OutputBaseFilename=EXTENSION_NAME-Setup-{#AppVersion} Compression=lzma SolidCompression=yes MinVersion=10.0.19041 - [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" @@ -339,12 +360,11 @@ Name: "english"; MessagesFile: "compiler:Default.isl" Source: "bin\Release\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs [Icons] -Name: "{group}\"; Filename: "{app}\.exe" +Name: "{group}\DISPLAY_NAME"; Filename: "{app}\EXTENSION_NAME.exe" [Registry] -Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{}}"; ValueData: "" ; Replace , note: do not replace SOFTWARE\Classes\CLSID\ portion -Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{}}\LocalServer32"; ValueData: "{app}\.exe -RegisterProcessAsComServer" ; Replace , note: do not replace SOFTWARE\Classes\CLSID\ portion - +Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}"; ValueData: "EXTENSION_NAME" +Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; ValueData: "{app}\EXTENSION_NAME.exe -RegisterProcessAsComServer" ``` Note: you can test this locally by having .NET 9 `dotnet` and Inno Setup (todo add links) @@ -373,7 +393,117 @@ mkdir .github/workflows ``` 1. In the `workflows` directory, create a new file called `release-extension.yml`. -1. Copy the contents of [release-extension-template.yml](https://github.com/chatasweetie/CmdPalExtensions/blob/main/.github/workflows/release-extension-template.yml) to your local file. This file is a Github Action scrip that does the following: +1. Add the following content to the new file: + +```yml +# TEMPLATE: Extension EXE Installer Build and Release Workflow +# +# To use this template for a new extension: +# 1. Copy this file to a new workflow file (e.g., release-myextension-exe.yml) +# 2. Replace all instances of DEVELOPER_NAME with your developer name (e.g., Your Name Here) +# 3. Replace all instances of GITHUB_REPO_URL with your GitHub repository URL (e.g., https://github.com/yourusername/YourRepository) +# 4. Replace all instances of DISPLAY_NAME with your display name (e.g., My Extension) +# 5. Replace all instances of EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +# 6. Replace all instances of FOLDER_NAME with your project folder name (e.g., CmdPalMyExtension) +# 7. Replace all instances of GENERATE-NEW-GUID-HERE with your project's CLSID +# 8. Update the default version in the build script to match your project file + +name: DISPLAY_NAME - Build EXE Installer + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number (leave empty to auto-detect)' + required: false + type: string + release_notes: + description: 'What is new in this version' + required: false + default: 'New release with latest updates and improvements.' + type: string + +jobs: + build: + runs-on: windows-2022 + permissions: + contents: write + actions: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup .NET 9 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.0.x' + + - name: Install Inno Setup + run: choco install innosetup -y --no-progress + shell: pwsh + + - name: Get version from project + id: version + run: | + if ("${{ github.event.inputs.version }}" -ne "") { + $version = "${{ github.event.inputs.version }}" + } else { + $projectFile = "FOLDER_NAME/FOLDER_NAME/EXTENSION_NAME.csproj" + $xml = [xml](Get-Content $projectFile) + $version = $xml.Project.PropertyGroup.AppxPackageVersion | Select-Object -First 1 + if (-not $version) { throw "Version not found in project file" } + } + echo "VERSION=$version" >> $env:GITHUB_OUTPUT + Write-Host "Using version: $version" + shell: pwsh + + - name: Build EXE installer using PowerShell script + run: | + Set-Location "FOLDER_NAME/FOLDER_NAME" + .\build-exe.ps1 -Version "${{ steps.version.outputs.VERSION }}" + shell: pwsh + + - name: Upload installer artifact + uses: actions/upload-artifact@v4 + with: + name: EXTENSION_NAME-installer + path: FOLDER_NAME/FOLDER_NAME/bin/Release/installer/*.exe + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: EXTENSION_NAME-v${{ steps.version.outputs.VERSION }} + name: "DISPLAY_NAME v${{ steps.version.outputs.VERSION }}" + body: | + ## 🎯 DISPLAY_NAME + + ${{ github.event.inputs.release_notes }} + + ## 📦 Installation + + 1. Download `EXTENSION_NAME-Setup-${{ steps.version.outputs.VERSION }}.exe` + 2. Run as Administrator + 3. Extension will be available in Command Palette + + ## 🔗 More Information + + Repository: GITHUB_REPO_URL + files: FOLDER_NAME/FOLDER_NAME/bin/Release/installer/*.exe + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Build summary + run: | + Write-Host "🎉 DISPLAY_NAME Release Complete!" -ForegroundColor Green + Write-Host "Version: ${{ steps.version.outputs.VERSION }}" -ForegroundColor Yellow + Write-Host "📁 Installer uploaded to GitHub Release" -ForegroundColor Green + shell: pwsh +``` + +This file is a Github Action scrip that does the following: - Setup (.NET, Inno Setup) - Get Version (simple version detection) @@ -384,7 +514,7 @@ mkdir .github/workflows - DEVELOPER_NAME - GITHUB_REPO_URL - EXTENSION_NAME - - DISPLAY_NAME + - EXTENSION_NAME - FOLDER_NAME - GENERATE-NEW-GUID-HERE 1. git commit the 3 new files: `build-exe.ps1`, `setup.iss`,`release-extension.yml` From e0823cac1ca94449e7a348cbacbd81c39e19ba62 Mon Sep 17 00:00:00 2001 From: Jessica Dene Earley-Cha <12740421+chatasweetie@users.noreply.github.com> Date: Tue, 14 Oct 2025 12:05:20 -0700 Subject: [PATCH 03/13] correct formatting, add context to the two processes and about github actions --- .../command-palette/publish-extension.md | 93 ++++++++++++------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index de65af077c..dd69d030c6 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -34,6 +34,8 @@ You can run this command from the "Run commands" command in Command Palette, fro > [!NOTE] > This guide provides basic Microsoft Store publishing steps specific to Command Palette extensions. For comprehensive Microsoft Store publishing guidance, including detailed submission requirements, certification processes, and best practices, see [Publish Windows apps and games](https://learn.microsoft.com/windows/apps/publish/). +Publishing to the Microsoft Store provides your extension with wide reach across Windows devices and automatic update delivery to users. This guide walks you through the complete process from setting up your Partner Center account to building MSIX packages and submitting your extension for certification. You'll learn how to prepare your extension's manifest files, create the required bundle packages, and navigate the Partner Center submission workflow to get your extension published successfully. + ### Prerequisites > [!IMPORTANT] @@ -120,16 +122,16 @@ You can run this command from the "Run commands" command in Command Palette, fro > [!NOTE] > If `makeappx` isn't recognized, check which version of Windows SDK you have installed: - > - > ```powershell - > Get-ChildItem "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v*" | Select-Object PSChildName - > ``` - > - > Then update the following script with the version number: - > - > ```powershell - > & "C:\Program Files (x86)\Windows Kits\\bin\[version]\x64\makeappx.exe" bundle /f bundle_mapping.txt /p __Bundle.msixbundle - > ``` + > + > ```powershell + > Get-ChildItem "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v*" | Select-Object PSChildName + > ``` + > + > Then update the following script with the version number: + > + > ```powershell + > & "C:\Program Files (x86)\Windows Kits\\bin\[version]\x64\makeappx.exe" bundle /f bundle_mapping.txt /p __Bundle.msixbundle + > ``` 1. Locate the bundle: @@ -196,10 +198,13 @@ Dependencies: ## Guide to WinGet publishing +Publishing to WinGet is the recommended distribution method for Command Palette extensions as it enables automatic discovery and installation directly within Command Palette. This guide covers the majority of the WinGet publication process, from preparing your project and creating build scripts to setting up GitHub Actions automation and submitting your first package manifest. You'll learn how to create installer packages, configure automated builds, and navigate the WinGet submission workflow to make your extension easily discoverable and installable for users. + ### Requirements - [GitHub CLI](https://cli.github.com/) - WingetCreate + ```powershell # Install wingetcreate if not already installed winget install Microsoft.WingetCreate @@ -208,9 +213,7 @@ Dependencies: wingetcreate --version ``` -### Prepare Github Repo -TODO: add instructions on adding secreats ### Prepare the project @@ -224,6 +227,7 @@ TODO: add instructions on adding secreats 1. Create a `build-exe.ps1` file, for a simple extension you can copy and customize the following: **Template: `build-exe.ps1`** + ```powershell # TEMPLATE: PowerShell Build Script for Command Palette Extensions # @@ -328,6 +332,7 @@ Write-Host "🎉 Build completed successfully!" -ForegroundColor Green 1. Create a `setup-template.iss` file, for a simple extension you can copy and customize the following: **Template: `setup-template.iss`** + ```ini ; TEMPLATE: Inno Setup Script for Command Palette Extensions ; @@ -336,7 +341,7 @@ Write-Host "🎉 Build completed successfully!" -ForegroundColor Green ; 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) ; 3. Replace DISPLAY_NAME with your extension's display name (e.g., My Extension) ; 4. Replace DEVELOPER_NAME with your name (e.g., Your Name Here) -; 5. Replace CLSID-HERE with a new CLSID for COM registration +; 5. Replace CLSID-HERE with extensions CLSID ; 6. Update the default version to match your project file #define AppVersion "0.0.1.0" @@ -367,23 +372,30 @@ Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}"; ValueData: "EXTENSI Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; ValueData: "{app}\EXTENSION_NAME.exe -RegisterProcessAsComServer" ``` -Note: you can test this locally by having .NET 9 `dotnet` and Inno Setup (todo add links) - -```powershell -# verify .Net 9 is installed -dotnet --version - -# verify Inno Setup is installed -Test-Path "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" - -# build installer, this will take a while -.\build-exe.ps1 -Version "0.0.1.0" +> [!TIP] +> You can test this locally by having [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) and [Inno Setup](https://jrsoftware.org/isdl.php) installed. +> +> ```powershell +> # verify .Net 9 is installed +> dotnet --version +> +> # verify Inno Setup is installed +> Test-Path "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" +> +> # build installer, this will take a while +> .\build-exe.ps1 -Version "0.0.1.0" +> +> # verify that -Setup-0.0.1.0.exe is listed +> Get-ChildItem "bin\Release\installer\" -File +> ``` + +### Automate with GitHub Actions -# verify that -Setup-0.0.1.0.exe is listed -Get-ChildItem "bin\Release\installer\" -File -``` +> [!NOTE] +> **What are GitHub Actions?** +> GitHub Actions is a CI/CD platform that automates software workflows directly in your GitHub repository. For Command Palette extensions, GitHub Actions can automatically build your installer whenever you push code changes, create releases, and even submit updates to WinGet - eliminating manual build steps and ensuring consistent, reproducible builds. -TODO: Explain Github Actions briefly +Now we'll set up GitHub Actions to automate the build and release process: 1. `cd ..` up a directory, you should be in the directory that contains `.sln` 1. create a new repo: @@ -405,7 +417,6 @@ mkdir .github/workflows # 4. Replace all instances of DISPLAY_NAME with your display name (e.g., My Extension) # 5. Replace all instances of EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) # 6. Replace all instances of FOLDER_NAME with your project folder name (e.g., CmdPalMyExtension) -# 7. Replace all instances of GENERATE-NEW-GUID-HERE with your project's CLSID # 8. Update the default version in the build script to match your project file name: DISPLAY_NAME - Build EXE Installer @@ -505,11 +516,12 @@ jobs: This file is a Github Action scrip that does the following: - - Setup (.NET, Inno Setup) - - Get Version (simple version detection) - - Build App (straightforward dotnet publish) - - Create Installer (simple Inno Setup call) - - Upload Results (clear artifact + release steps) +- Setup (.NET, Inno Setup) +- Get Version (simple version detection) +- Build App (straightforward dotnet publish) +- Create Installer (simple Inno Setup call) +- Upload Results (clear artifact + release steps) + 1. Update the placeholders in `release-extension.yml`: - DEVELOPER_NAME - GITHUB_REPO_URL @@ -526,6 +538,15 @@ This file is a Github Action scrip that does the following: The inaugural release of the for Command Palette..." ``` +#### GitHub Actions validation + +Verify your GitHub Actions setup by checking: + +- ✅ GitHub Action workflow runs successfully without errors +- ✅ Installer EXE is created and uploaded to GitHub Release + +**Typical build time**: 5-10 minutes for the GitHub Action to complete. + ### WinGet submission > [!IMPORTANT] @@ -544,7 +565,9 @@ This file is a Github Action scrip that does the following: # Use your actual GitHub release URL (example with version 0.0.1 for first release) wingetcreate new "https://github.com///releases/download/-v0.0.1/-Setup-0.0.1.exe" ``` - Note: FOr the Github Release URL, you can go to the release page, under **Assets** you can right click the .exe file and + + > [!TIP] + > To get the GitHub Release URL: Go to your release page, under **Assets**, right-click the `.exe` file and select "Copy link address". 1. When `wingetcreate` prompts you, press **Enter** if the suggested response is pulled from the EXE file, for example: `PackageIdentifier`, `PackageVersion`, `Publisher`, etc. - **For optional modification questions**, answer **No**: From 79e4a305a70f621a5073d26288e6e84cedf7c2a5 Mon Sep 17 00:00:00 2001 From: Jessica Dene Earley-Cha <12740421+chatasweetie@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:05:28 -0700 Subject: [PATCH 04/13] minor formatting changes, moved two requirements for winget from ### to being bold --- .../command-palette/publish-extension.md | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index dd69d030c6..734c6986a7 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -31,11 +31,11 @@ You can run this command from the "Run commands" command in Command Palette, fro ## Guide to Microsoft Store publishing +Publishing to the Microsoft Store provides your extension with wide reach across Windows devices and automatic update delivery to users. This guide walks you through the complete process from setting up your Partner Center account to building MSIX packages and submitting your extension for certification. You'll learn how to prepare your extension's manifest files, create the required bundle packages, and navigate the Partner Center submission workflow to get your extension published successfully. + > [!NOTE] > This guide provides basic Microsoft Store publishing steps specific to Command Palette extensions. For comprehensive Microsoft Store publishing guidance, including detailed submission requirements, certification processes, and best practices, see [Publish Windows apps and games](https://learn.microsoft.com/windows/apps/publish/). -Publishing to the Microsoft Store provides your extension with wide reach across Windows devices and automatic update delivery to users. This guide walks you through the complete process from setting up your Partner Center account to building MSIX packages and submitting your extension for certification. You'll learn how to prepare your extension's manifest files, create the required bundle packages, and navigate the Partner Center submission workflow to get your extension published successfully. - ### Prerequisites > [!IMPORTANT] @@ -85,7 +85,7 @@ Publishing to the Microsoft Store provides your extension with wide reach across ### Build MSIX -1. In the terminal, change to the `\` directory. +1. In the terminal, move to the `\` directory. 1. Create an x64 build MSIX with the following command: ```powershell @@ -154,30 +154,28 @@ Verify your MSIX build is ready by checking: If any items are missing or failed, review the build commands and check for error messages before continuing. - ### Microsoft Store submission 1. Navigate to the [Microsoft Partner Center](https://partner.microsoft.com/dashboard/home) and open your newly created extension project. 1. In **Packages**, upload the created MSIX bundle. 1. Complete the rest of the submission. The following suggestions can help you: 1. In **Languages supported in packages**, under your supported language (for example, English (United States)), in **Description**, make sure to include ` integrates with the Windows Command Palette to...` - 1. **Tip**: Add additional testing information. - - In the left navigation, locate **Supplemental info** and select **Additional Testing Information**. Here's an [example](https://github.com/chatasweetie/CmdPalExtensions/blob/main/microsoftStoreResources/TesterInstructions.txt). + 1. In the left navigation, locate **Supplemental info** and select **Additional Testing Information**. Add instructions about needing Powertoys and Command Palette. Here's an [example](https://github.com/chatasweetie/CmdPalExtensions/blob/main/microsoftStoreResources/TesterInstructions.txt). 1. Submit your extension to the store. After submission, Microsoft will review your extension for certification. Monitor your submission status in Partner Center and check for email notifications about approval. Once approved, your extension will be available in the Microsoft Store within a few hours. ## WinGet +Publishing packages to WinGet is the recommended way to share your extensions with users. Extension packages that are listed on WinGet can be discovered and installed directly from Command Palette. + > [!TIP] > **What is WinGet?** > WinGet is Microsoft's open-source command-line package manager for Windows. It's similar to package managers like npm or pip, but for Windows applications. Publishing to WinGet allows users to install your extension with a simple `winget install` command and enables automatic discovery within Command Palette. -Publishing packages to WinGet is the recommended way to share your extensions with users. Extension packages that are listed on WinGet can be discovered and installed directly from Command Palette. - Before submitting your manifest to WinGet, check the following two requirements: -### Add the `windows-commandpalette-extension` tag +**Add the `windows-commandpalette-extension` tag** Command Palette uses the special `windows-commandpalette-extension` tag to discover extensions. Make sure that your manifest includes this tag so that Command Palette can discover your extension. Add the following code to each `.locale.*.yaml` file in your manifest: @@ -186,7 +184,7 @@ Tags: - windows-commandpalette-extension ``` -### Ensure WindowsAppSdk is listed as a dependency +**Ensure WindowsAppSdk is listed as a dependency** If you're using Windows App SDK, make sure that it's listed as a dependency of your package. Add the following code to your `.installer.yaml` manifest: @@ -213,16 +211,11 @@ Publishing to WinGet is the recommended distribution method for Command Palette wingetcreate --version ``` - - ### Prepare the project 1. In `.csproj`, from the ``: - Remove `win-$(Platform).pubxml` - Add `None` -1. `cd` into `CmdPalRandomRiddleExtension\CmdPalRandomRiddleExtension\Properties\` - - 1. `cd` into the directory that contains your `.cs` 1. Create a `build-exe.ps1` file, for a simple extension you can copy and customize the following: @@ -317,7 +310,7 @@ Write-Host "🎉 Build completed successfully!" -ForegroundColor Green 1. Locate `CLSID` 1. Open the extension's main `.cs` file (for example, `.cs`). 1. Look for the `[Guid("...")]` attribute above the class declaration. - 1. This GUID is your CLSID - copy it exactly as shown. + 1. This GUID is your CLSID - Keep note of this because it will be used in th next step ```csharp // Example from .cs @@ -550,12 +543,8 @@ Verify your GitHub Actions setup by checking: ### WinGet submission > [!IMPORTANT] -> The first submission must be manual. A GitHub Action template will be linked at the end for post-first submission updates. - -**Why manual first?** +> The first submission must be manual. `wingetcreate new` requires interactive input for package details -- `wingetcreate new` requires interactive input for package details -- GitHub Actions can't provide interactive console input #### Manual first submission From 1e991d258d060001ed11ef0863b7646d95911fa3 Mon Sep 17 00:00:00 2001 From: Jessica Dene Earley-Cha <12740421+chatasweetie@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:14:08 -0700 Subject: [PATCH 05/13] add more microsoft store image and Partner Center details --- .../command-palette/publish-extension.md | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index 734c6986a7..9c21820d0b 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -34,7 +34,7 @@ You can run this command from the "Run commands" command in Command Palette, fro Publishing to the Microsoft Store provides your extension with wide reach across Windows devices and automatic update delivery to users. This guide walks you through the complete process from setting up your Partner Center account to building MSIX packages and submitting your extension for certification. You'll learn how to prepare your extension's manifest files, create the required bundle packages, and navigate the Partner Center submission workflow to get your extension published successfully. > [!NOTE] -> This guide provides basic Microsoft Store publishing steps specific to Command Palette extensions. For comprehensive Microsoft Store publishing guidance, including detailed submission requirements, certification processes, and best practices, see [Publish Windows apps and games](https://learn.microsoft.com/windows/apps/publish/). +> This guide provides basic Microsoft Store publishing steps specific to Command Palette extensions. For comprehensive Microsoft Store publishing guidance, including detailed submission requirements, certification processes, and best practices, see [Publish Windows apps and games](/windows/apps/publish/). ### Prerequisites @@ -42,8 +42,26 @@ Publishing to the Microsoft Store provides your extension with wide reach across > **What is Partner Center?** > Partner Center is Microsoft's portal for app developers to manage Microsoft Store submissions, track analytics, and handle app certification. -- [Register as a Windows app developer in Partner Center](https://learn.microsoft.com/en-us/windows/apps/publish/partner-center/partner-center-developer-account) -- Create all required app icons and ensure they're properly sized ([Create icons using Visual Studio's asset generation tool](https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/visual-studio-asset-generation)) +- [Register as a Windows app developer in Partner Center](../../apps/publish/partner-center/partner-center-developer-account) +- Create all required app icons and ensure they're properly sized ([Create icons using Visual Studio's asset generation tool](../../apps/design/style/iconography/visual-studio-asset-generation)) + +> [!TIP] +> - Before using the tool, delete all the default images that were provided via the template. +> - Make sure you generate the following files: +> +> | File Name | Size | +> |--------------------------|------------| +> | Square44x44Logo | 44×44 | +> | Square71x71Logo | 71×71 | +> | SmallTile.png | 71×71 | +> | Square150x150Logo | 150×150 | +> | Square310x310Logo | 310×310 | +> | LargeTile.png | 310×310 | +> | Wide310x150Logo | 310×150 | +> | SplashScreen | 620×300 | +> | BadgeLogo | 24×24 | +> | StoreLogo | 50×50 | +> | Screenshot (Desktop) | ≥1366×768 | ### Set up Microsoft Store @@ -54,32 +72,41 @@ Publishing to the Microsoft Store provides your extension with wide reach across 1. Create a name or reserve a product name. 1. Start the submission and complete as much as you can until you reach the **Packages** section. 1. In the left navigation, under **Product Management**, select **Product identity**. -1. Note the `Package/Identity/Name`, `Package/Identity/Publisher`, and `Package/Properties/PublisherDisplayName` for the following steps. +1. Copy the following values for use in the next steps: + +> [!IMPORTANT] +> **Copy these values from Partner Center:** +> +> - **Package/Identity/Name**: `_________________` +> - **Package/Identity/Publisher**: `_________________` +> - **Package/Properties/PublisherDisplayName**: `_________________` +> +> You'll use these exact values in the code examples below. ### Prepare the extension 1. In your IDE, open `\Package.appxmanifest`. -1. Update the publisher and publisher display name: +1. Replace the values with the information you copied from Partner Center: ```xml - Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" + Name="YOUR_PACKAGE_IDENTITY_NAME_HERE" + Publisher="YOUR_PACKAGE_IDENTITY_PUBLISHER_HERE" Version="0.0.1.0" /> - TemplateDisplayName - A Lone Developer + YourExtensionDisplayName + YOUR_PUBLISHER_DISPLAY_NAME_HERE Assets\StoreLogo.png ``` 1. In your IDE, open `.csproj`. -1. Locate the `PropertyGroup` element and add the following properties: +1. Locate the `PropertyGroup` element and add the following properties using your Partner Center values: ```xml - Package/Identity/Name - CN=########-####-####-####-############ + YOUR_PACKAGE_IDENTITY_NAME_HERE + YOUR_PACKAGE_IDENTITY_PUBLISHER_HERE 0.0.1.0 ``` From b7d770520f8a0864ce79e60316cf1af08c55046c Mon Sep 17 00:00:00 2001 From: Jessica Dene Earley-Cha <12740421+chatasweetie@users.noreply.github.com> Date: Fri, 24 Oct 2025 15:24:18 -0700 Subject: [PATCH 06/13] added more details about required images, made image upload as a wilecard and point microsoft store expected naming, updated $projectFile file path to be one repo lower due to single extension different structure than my multi extension --- .../command-palette/publish-extension.md | 88 +++++++++++++++---- 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index 9c21820d0b..b8a2bd1710 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -46,22 +46,18 @@ Publishing to the Microsoft Store provides your extension with wide reach across - Create all required app icons and ensure they're properly sized ([Create icons using Visual Studio's asset generation tool](../../apps/design/style/iconography/visual-studio-asset-generation)) > [!TIP] -> - Before using the tool, delete all the default images that were provided via the template. +> - [List of icons and variations](/windows/apps/design/style/iconography/app-icon-construction#complete-list-of-icons-and-variations) > - Make sure you generate the following files: -> +> > | File Name | Size | > |--------------------------|------------| > | Square44x44Logo | 44×44 | -> | Square71x71Logo | 71×71 | -> | SmallTile.png | 71×71 | +> | SmallTile | 71×71 | > | Square150x150Logo | 150×150 | -> | Square310x310Logo | 310×310 | -> | LargeTile.png | 310×310 | +> | LargeTile | 310×310 | > | Wide310x150Logo | 310×150 | > | SplashScreen | 620×300 | -> | BadgeLogo | 24×24 | > | StoreLogo | 50×50 | -> | Screenshot (Desktop) | ≥1366×768 | ### Set up Microsoft Store @@ -95,14 +91,14 @@ Publishing to the Microsoft Store provides your extension with wide reach across Version="0.0.1.0" /> - YourExtensionDisplayName + YOUR_EXTENSION_DISPLAY_NAME YOUR_PUBLISHER_DISPLAY_NAME_HERE - Assets\StoreLogo.png + Assets\StoreLogo.png ``` 1. In your IDE, open `.csproj`. -1. Locate the `PropertyGroup` element and add the following properties using your Partner Center values: +1. Locate a `PropertyGroup` element (with no conditions) and add the following properties using your Partner Center values: ```xml YOUR_PACKAGE_IDENTITY_NAME_HERE @@ -110,35 +106,89 @@ Publishing to the Microsoft Store provides your extension with wide reach across 0.0.1.0 ``` +1. Update the ItemGroup for images to get all of them by removing: + +```xml + + + + + + + + +``` + +with + +```xml + + + +``` + +1. Under the `` you just updated, add: + +```xml + + + + + + + + + +``` + ### Build MSIX 1. In the terminal, move to the `\` directory. 1. Create an x64 build MSIX with the following command: ```powershell - dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=x64 + dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=x64 -p:AppxPackageDir="AppPackages\x64\" + ``` 1. Create an ARM64 build MSIX with the following command: ```powershell - dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=ARM64 + dotnet build --configuration Release -p:GenerateAppxPackageOnBuild=true -p:Platform=ARM64 -p:AppxPackageDir="AppPackages\ARM64\" ``` +> [!NOTE] +> The `AppxPackageDir="AppPackages\x64\"` is needed so that the ARM64 build doesn't overwrite the x64 build + 1. Locate the MSIX files: ```powershell - cd ; dir bin -Recurse -Filter "*.msix" + dir AppPackages -Recurse -Filter "*.msix" ``` +> [!TIP] +> If you do not see your MSIX files, try `dir bin\ -Recurse -Filter "*.msix"` + 1. Note the locations of the `__x64.msix` and `__arm64.msix` files. -1. Create a new `bundle_mapping.txt` file and include the following content, updating the paths to your MSIX files: +1. In your current location in the directory, create a new `bundle_mapping.txt` file and include the following content, updating the paths to your MSIX files: ```text [Files] - "bin\x64\Release\PATH\__x64.msix" "__x64.msix" - "bin\ARM64\Release\PATH\__arm64.msix" "__arm64.msix" + "AppPackages\__x64_Test\__x64.msix" "__x64.msix" + "AppPackages\t__arm64_Test\__arm64.msix" "__arm64.msix" ``` 1. Create a bundle that combines both architectures into a single package for Microsoft Store submission. Update the `` and ``: @@ -157,7 +207,7 @@ Publishing to the Microsoft Store provides your extension with wide reach across > Then update the following script with the version number: > > ```powershell - > & "C:\Program Files (x86)\Windows Kits\\bin\[version]\x64\makeappx.exe" bundle /f bundle_mapping.txt /p __Bundle.msixbundle + > & "C:\Program Files (x86)\Windows Kits\\App Certification Kit\makeappx.exe" bundle /f bundle_mapping.txt /p __Bundle.msixbundle > ``` 1. Locate the bundle: @@ -480,7 +530,7 @@ jobs: if ("${{ github.event.inputs.version }}" -ne "") { $version = "${{ github.event.inputs.version }}" } else { - $projectFile = "FOLDER_NAME/FOLDER_NAME/EXTENSION_NAME.csproj" + $projectFile = "FOLDER_NAME/EXTENSION_NAME.csproj" $xml = [xml](Get-Content $projectFile) $version = $xml.Project.PropertyGroup.AppxPackageVersion | Select-Object -First 1 if (-not $version) { throw "Version not found in project file" } From a3a9da7643dd728320caddd77b2ac3e85ccf7feb Mon Sep 17 00:00:00 2001 From: Jessica Dene Earley-Cha <12740421+chatasweetie@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:33:12 -0700 Subject: [PATCH 07/13] made changes based on Zachary's review --- .../command-palette/publish-extension.md | 146 +++++++++--------- 1 file changed, 72 insertions(+), 74 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index b8a2bd1710..233b2f818d 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -198,16 +198,16 @@ with ``` > [!NOTE] - > If `makeappx` isn't recognized, check which version of Windows SDK you have installed: + > If `makeappx` isn't recognized, find it on your machine: > > ```powershell - > Get-ChildItem "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v*" | Select-Object PSChildName + > $arch = switch ($env:PROCESSOR_ARCHITECTURE) { "AMD64" { "x64" } "x86" { "x86" } "ARM64" { "arm64" } default { "x64" } }; Write-Host "Detected: $arch"; $found = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\$arch\makeappx.exe" -ErrorAction SilentlyContinue | Sort-Object Name -Descending | Select-Object -First 1; if ($found) { Write-Host "SUCCESS: $($found.FullName)" -ForegroundColor Green; $found.FullName } else { Write-Host "Not found for $arch" -ForegroundColor Red } > ``` > - > Then update the following script with the version number: + > Then update the following script your machine's path: > > ```powershell - > & "C:\Program Files (x86)\Windows Kits\\App Certification Kit\makeappx.exe" bundle /f bundle_mapping.txt /p __Bundle.msixbundle + > & "\makeappx.exe" bundle /f bundle_mapping.txt /p __Bundle.msixbundle > ``` 1. Locate the bundle: @@ -293,7 +293,65 @@ Publishing to WinGet is the recommended distribution method for Command Palette 1. In `.csproj`, from the ``: - Remove `win-$(Platform).pubxml` - Add `None` -1. `cd` into the directory that contains your `.cs` +1. Locate `CLSID` + 1. Open the extension's main `.cs` file (for example, `.cs`). + 1. Look for the `[Guid("...")]` attribute above the class declaration. + 1. This GUID is your CLSID - Keep note of this because it will be used in th next step + + ```csharp + // Example from .cs + [Guid("0ab5d8ab-b206-4023-99f0-97dde26e14f2")] // This is the CLSID + public sealed partial class : IExtension + ``` + + > [!NOTE] + > **What is a CLSID?** + > A CLSID (Class Identifier) is a unique identifier that Windows uses to identify COM (Component Object Model) components. Each Command Palette extension needs a unique CLSID so Windows can properly register and load your extension. This GUID is automatically generated when you create your extension project. + +1. Make sure that your in the directory that contains your `.cs` for the next two files being created. +1. Create a `setup-template.iss` file, for a simple extension you can copy and customize the following: + +**Template: `setup-template.iss`** + +```ini +; TEMPLATE: Inno Setup Script for Command Palette Extensions +; +; To use this template for a new extension: +; 1. Copy this file to your extension's project folder as "setup-template.iss" +; 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +; 3. Replace DISPLAY_NAME with your extension's display name (e.g., My Extension) +; 4. Replace DEVELOPER_NAME with your name (e.g., Your Name Here) +; 5. Replace CLSID-HERE with extensions CLSID +; 6. Update the default version to match your project file + +#define AppVersion "0.0.1.0" + +[Setup] +AppId={{GUID-HERE}} +AppName=DISPLAY_NAME +AppVersion={#AppVersion} +AppPublisher=DEVELOPER_NAME +DefaultDirName={autopf}\EXTENSION_NAME +OutputDir=bin\Release\installer +OutputBaseFilename=EXTENSION_NAME-Setup-{#AppVersion} +Compression=lzma +SolidCompression=yes +MinVersion=10.0.19041 + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Files] +Source: "bin\Release\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs + +[Icons] +Name: "{group}\DISPLAY_NAME"; Filename: "{app}\EXTENSION_NAME.exe" + +[Registry] +Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}"; ValueData: "EXTENSION_NAME" +Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; ValueData: "{app}\EXTENSION_NAME.exe -RegisterProcessAsComServer" +``` + 1. Create a `build-exe.ps1` file, for a simple extension you can copy and customize the following: **Template: `build-exe.ps1`** @@ -304,19 +362,18 @@ Publishing to WinGet is the recommended distribution method for Command Palette # To use this template for a new extension: # 1. Copy this file to your extension's project folder as "build-exe.ps1" # 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) -# 2. Replace with your extension version (e.g., 0.0.1.0) -# 3. Update the default version to match your project file's AppxPackageVersion -# 4. Ensure you have a setup-template.iss file in the same directory +# 3. Replace with your extension version (e.g., 0.0.1.0) +# 4. Update the default version to match your project file's AppxPackageVersion param( [string]$Configuration = "Release", - [string]$Version = "", # UPDATE: Change this to match your project's default version + [string]$Version = "", [string]$Platform = "x64" ) $ErrorActionPreference = "Stop" -Write-Host "Building EXTENSION_NAME EXE installer..." -ForegroundColor Green +Write-Host "Building EXTENSION_NAME EXE installer..." -ForegroundColor Green Write-Host "Version: $Version" -ForegroundColor Yellow $ProjectDir = Split-Path -Parent $MyInvocation.MyCommand.Path @@ -384,64 +441,6 @@ if (Test-Path $InnoSetupPath) { Write-Host "🎉 Build completed successfully!" -ForegroundColor Green ``` -1. Locate `CLSID` - 1. Open the extension's main `.cs` file (for example, `.cs`). - 1. Look for the `[Guid("...")]` attribute above the class declaration. - 1. This GUID is your CLSID - Keep note of this because it will be used in th next step - - ```csharp - // Example from .cs - [Guid("0ab5d8ab-b206-4023-99f0-97dde26e14f2")] // This is the CLSID - public sealed partial class : IExtension - ``` - - > [!NOTE] - > **What is a CLSID?** - > A CLSID (Class Identifier) is a unique identifier that Windows uses to identify COM (Component Object Model) components. Each Command Palette extension needs a unique CLSID so Windows can properly register and load your extension. This GUID is automatically generated when you create your extension project. - -1. Create a `setup-template.iss` file, for a simple extension you can copy and customize the following: - -**Template: `setup-template.iss`** - -```ini -; TEMPLATE: Inno Setup Script for Command Palette Extensions -; -; To use this template for a new extension: -; 1. Copy this file to your extension's project folder as "setup-template.iss" -; 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) -; 3. Replace DISPLAY_NAME with your extension's display name (e.g., My Extension) -; 4. Replace DEVELOPER_NAME with your name (e.g., Your Name Here) -; 5. Replace CLSID-HERE with extensions CLSID -; 6. Update the default version to match your project file - -#define AppVersion "0.0.1.0" - -[Setup] -AppId={{GUID-HERE}} -AppName=DISPLAY_NAME -AppVersion={#AppVersion} -AppPublisher=DEVELOPER_NAME -DefaultDirName={autopf}\EXTENSION_NAME -OutputDir=bin\Release\installer -OutputBaseFilename=EXTENSION_NAME-Setup-{#AppVersion} -Compression=lzma -SolidCompression=yes -MinVersion=10.0.19041 - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Files] -Source: "bin\Release\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs - -[Icons] -Name: "{group}\DISPLAY_NAME"; Filename: "{app}\EXTENSION_NAME.exe" - -[Registry] -Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}"; ValueData: "EXTENSION_NAME" -Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; ValueData: "{app}\EXTENSION_NAME.exe -RegisterProcessAsComServer" -``` - > [!TIP] > You can test this locally by having [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) and [Inno Setup](https://jrsoftware.org/isdl.php) installed. > @@ -482,12 +481,11 @@ mkdir .github/workflows # # To use this template for a new extension: # 1. Copy this file to a new workflow file (e.g., release-myextension-exe.yml) -# 2. Replace all instances of DEVELOPER_NAME with your developer name (e.g., Your Name Here) -# 3. Replace all instances of GITHUB_REPO_URL with your GitHub repository URL (e.g., https://github.com/yourusername/YourRepository) -# 4. Replace all instances of DISPLAY_NAME with your display name (e.g., My Extension) -# 5. Replace all instances of EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) -# 6. Replace all instances of FOLDER_NAME with your project folder name (e.g., CmdPalMyExtension) -# 8. Update the default version in the build script to match your project file +# 2. Replace all instances of GITHUB_REPO_URL with your GitHub repository URL (e.g., https://github.com/yourusername/YourRepository) +# 3. Replace all instances of DISPLAY_NAME with your display name (e.g., My Extension) +# 4. Replace all instances of EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +# 5. Replace all instances of FOLDER_NAME with your project folder name (e.g., CmdPalMyExtension) +# 6. Update the default version in the build script to match your project file name: DISPLAY_NAME - Build EXE Installer From c2b1618d79198868e73ecb880369a39ec7ae58e6 Mon Sep 17 00:00:00 2001 From: chatasweetie Date: Fri, 31 Oct 2025 14:19:13 -0700 Subject: [PATCH 08/13] update installer creation to include ARM64, add update github action --- .../command-palette/publish-extension.md | 231 ++++++++++++++---- 1 file changed, 178 insertions(+), 53 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index 233b2f818d..792d84291a 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -368,13 +368,15 @@ Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; Value param( [string]$Configuration = "Release", [string]$Version = "", - [string]$Platform = "x64" + [string]$Platform = @("x64", "arm64") ) $ErrorActionPreference = "Stop" Write-Host "Building EXTENSION_NAME EXE installer..." -ForegroundColor Green Write-Host "Version: $Version" -ForegroundColor Yellow +Write-Host "Platforms: $($Platforms -join ', ')" -ForegroundColor Yellow + $ProjectDir = Split-Path -Parent $MyInvocation.MyCommand.Path $ProjectFile = "$ProjectDir\EXTENSION_NAME.csproj" @@ -392,53 +394,76 @@ if (Test-Path "$ProjectDir\obj") { Write-Host "Restoring NuGet packages..." -ForegroundColor Yellow dotnet restore $ProjectFile -# Build and publish -Write-Host "Building and publishing application..." -ForegroundColor Yellow -dotnet publish $ProjectFile ` - --configuration $Configuration ` - --runtime "win-$Platform" ` - --self-contained true ` - --output "$ProjectDir\bin\$Configuration\win-$Platform\publish" - -if ($LASTEXITCODE -ne 0) { - throw "Build failed with exit code: $LASTEXITCODE" -} - +# Build for each platform +foreach ($Platform in $Platforms) { + Write-Host "`n=== Building $Platform ===" -ForegroundColor Cyan + + # Build and publish + Write-Host "Building and publishing $Platform application..." -ForegroundColor Yellow + dotnet publish $ProjectFile ` + --configuration $Configuration ` + --runtime "win-$Platform" ` + --self-contained true ` + --output "$ProjectDir\bin\$Configuration\win-$Platform\publish" + + if ($LASTEXITCODE -ne 0) { + Write-Warning "Build failed for $Platform with exit code: $LASTEXITCODE" + continue + } # Check if files were published -$publishDir = "$ProjectDir\bin\$Configuration\win-$Platform\publish" -$fileCount = (Get-ChildItem -Path $publishDir -Recurse -File).Count -Write-Host "✅ Published $fileCount files to $publishDir" -ForegroundColor Green - -# Update version in setup.iss -Write-Host "Updating installer script version..." -ForegroundColor Yellow -$setupTemplate = Get-Content "$ProjectDir\setup-template.iss" -Raw -$setupScript = $setupTemplate -replace '#define AppVersion ".*"', "#define AppVersion `"$Version`"" -$setupScript | Out-File -FilePath "$ProjectDir\setup.iss" -Encoding UTF8 - -# Create installer with Inno Setup -Write-Host "Creating installer with Inno Setup..." -ForegroundColor Yellow -$InnoSetupPath = "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" -if (-not (Test-Path $InnoSetupPath)) { - $InnoSetupPath = "${env:ProgramFiles}\Inno Setup 6\iscc.exe" -} + $publishDir = "$ProjectDir\bin\$Configuration\win-$Platform\publish" + $fileCount = (Get-ChildItem -Path $publishDir -Recurse -File).Count + Write-Host "✅ Published $fileCount files to $publishDir" -ForegroundColor Green -if (Test-Path $InnoSetupPath) { - & $InnoSetupPath "$ProjectDir\setup.iss" + # Create platform-specific setup script + Write-Host "Creating installer script for $Platform..." -ForegroundColor Yellow + $setupTemplate = Get-Content "$ProjectDir\setup-template.iss" -Raw + + # Update version + $setupScript = $setupTemplate -replace '#define AppVersion ".*"', "#define AppVersion `"$Version`"" + + # Update output filename to include platform suffix + $setupScript = $setupScript -replace 'OutputBaseFilename=(.*?)\{#AppVersion\}', "OutputBaseFilename=`$1{#AppVersion}-$Platform" + + # Update source path for the platform + $setupScript = $setupScript -replace 'Source: "bin\\Release\\win-x64\\publish', "Source: `"bin\Release\win-$Platform\publish" + + # Add architecture settings after [Setup] section + if ($Platform -eq "arm64") { + $setupScript = $setupScript -replace '(\[Setup\][^\[]*)(MinVersion=)', "`$1ArchitecturesAllowed=arm64`r`nArchitecturesInstallIn64BitMode=arm64`r`n`$2" + } else { + $setupScript = $setupScript -replace '(\[Setup\][^\[]*)(MinVersion=)', "`$1ArchitecturesAllowed=x64compatible`r`nArchitecturesInstallIn64BitMode=x64compatible`r`n`$2" + } - if ($LASTEXITCODE -eq 0) { - $installer = Get-ChildItem "$ProjectDir\bin\$Configuration\installer\*.exe" | Select-Object -First 1 - if ($installer) { - $sizeMB = [math]::Round($installer.Length / 1MB, 2) - Write-Host "✅ Created installer: $($installer.Name) ($sizeMB MB)" -ForegroundColor Green + $setupScript | Out-File -FilePath "$ProjectDir\setup-$Platform.iss" -Encoding UTF8 + + # Create installer with Inno Setup + Write-Host "Creating $Platform installer with Inno Setup..." -ForegroundColor Yellow + $InnoSetupPath = "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" + if (-not (Test-Path $InnoSetupPath)) { + $InnoSetupPath = "${env:ProgramFiles}\Inno Setup 6\iscc.exe" + } + + if (Test-Path $InnoSetupPath) { + & $InnoSetupPath "$ProjectDir\setup-$Platform.iss" + + if ($LASTEXITCODE -eq 0) { + $installer = Get-ChildItem "$ProjectDir\bin\$Configuration\installer\*-$Platform.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($installer) { + $sizeMB = [math]::Round($installer.Length / 1MB, 2) + Write-Host "✅ Created $Platform installer: $($installer.Name) ($sizeMB MB)" -ForegroundColor Green + } else { + Write-Warning "Installer file not found for $Platform" + } + } else { + Write-Warning "Inno Setup failed for $Platform with exit code: $LASTEXITCODE" } } else { - throw "Inno Setup failed with exit code: $LASTEXITCODE" + Write-Warning "Inno Setup not found at expected locations" } -} else { - Write-Warning "Inno Setup not found at expected locations" } -Write-Host "🎉 Build completed successfully!" -ForegroundColor Green +Write-Host "`n🎉 Build completed successfully!" -ForegroundColor Green ``` > [!TIP] @@ -537,17 +562,25 @@ jobs: Write-Host "Using version: $version" shell: pwsh - - name: Build EXE installer using PowerShell script + - name: Build EXE installers (x64 and ARM64) run: | Set-Location "FOLDER_NAME/FOLDER_NAME" - .\build-exe.ps1 -Version "${{ steps.version.outputs.VERSION }}" + .\build-exe.ps1 -Version "${{ steps.version.outputs.VERSION }}" -Platforms @("x64", "arm64") shell: pwsh - - name: Upload installer artifact + - name: Upload x64 installer artifact + uses: actions/upload-artifact@v4 + with: + name: EXTENSION_NAME-x64-installer + path: FOLDER_NAME/bin/Release/installer/*-x64.exe + if-no-files-found: error + + - name: Upload ARM64 installer artifact uses: actions/upload-artifact@v4 with: - name: EXTENSION_NAME-installer - path: FOLDER_NAME/FOLDER_NAME/bin/Release/installer/*.exe + name: EXTENSION_NAME-arm64-installer + path: FOLDER_NAME/bin/Release/installer/*-arm64.exe + if-no-files-found: warn - name: Create GitHub Release uses: softprops/action-gh-release@v1 @@ -555,20 +588,27 @@ jobs: tag_name: EXTENSION_NAME-v${{ steps.version.outputs.VERSION }} name: "DISPLAY_NAME v${{ steps.version.outputs.VERSION }}" body: | - ## 🎯 DISPLAY_NAME + ## 🎯 DISPLAY_NAME ${{ steps.version.outputs.VERSION }} + ## What's New ${{ github.event.inputs.release_notes }} ## 📦 Installation - 1. Download `EXTENSION_NAME-Setup-${{ steps.version.outputs.VERSION }}.exe` - 2. Run as Administrator - 3. Extension will be available in Command Palette + Download the installer for your system architecture: + + - **x64 (Intel/AMD)**: `DISPLAY_NAME-Setup-${{ steps.version.outputs.VERSION }}-x64.exe` + - **ARM64 (Windows on ARM)**: `DISPLAY_NAME-Setup-${{ steps.version.outputs.VERSION }}-arm64.exe` + + 1. Download the appropriate installer from the Assets section below + 2. Run the installer with administrator privileges + 3. The extension will be registered and available in Command Palette + ## 🔗 More Information Repository: GITHUB_REPO_URL - files: FOLDER_NAME/FOLDER_NAME/bin/Release/installer/*.exe + files: FOLDER_NAME/bin/Release/installer/*.exe draft: false prerelease: false env: @@ -594,7 +634,6 @@ This file is a Github Action scrip that does the following: - DEVELOPER_NAME - GITHUB_REPO_URL - EXTENSION_NAME - - EXTENSION_NAME - FOLDER_NAME - GENERATE-NEW-GUID-HERE 1. git commit the 3 new files: `build-exe.ps1`, `setup.iss`,`release-extension.yml` @@ -626,8 +665,8 @@ Verify your GitHub Actions setup by checking: 1. Activate interactive wingetcreate: ```powershell - # Use your actual GitHub release URL (example with version 0.0.1 for first release) - wingetcreate new "https://github.com///releases/download/-v0.0.1/-Setup-0.0.1.exe" + # Use your actual GitHub release URLs + wingetcreate new "" "" ``` > [!TIP] @@ -656,6 +695,92 @@ You can use GitHub Actions to update your already submitted projects to WinGet. Check out how [PowerToys](https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml) does this. +You can also use the following `.github\workflows\update-winget-randomriddle.yml`: + +``` +# Replace EXTENSION_NAME +# Replace GITHUB_USER_NAME +# Replace GITHUB_REPO +# Repalce YOUR_PACKAGE_IDENTITY_NAME_HERE with the AppxPackageIdentityName located in the .csproj + + +name: Update WinGet - EXTENSION_NAME Extension + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: 'Version number (e.g., 0.0.2.0)' + required: false + type: string + release_tag: + description: 'Release tag (e.g., EXTENSION_NAME-v0.0.2.0)' + required: false + type: string + +jobs: + update-winget: + # Only run if this is a EXTENSION_NAME release + if: github.event_name == 'workflow_dispatch' || startsWith(github.event.release.name, 'EXTENSION_NAME Extension') + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get release info + id: release + run: | + if ("${{ github.event_name }}" -eq "workflow_dispatch" -and "${{ inputs.version }}" -ne "") { + # Use provided inputs for manual trigger + echo "VERSION=${{ inputs.version }}" >> $env:GITHUB_OUTPUT + echo "TAG=${{ inputs.release_tag }}" >> $env:GITHUB_OUTPUT + } elseif ("${{ github.event_name }}" -eq "release") { + # Extract from release event + $version = "${{ github.event.release.tag_name }}" -replace "EXTENSION_NAME-v", "" + echo "VERSION=$version" >> $env:GITHUB_OUTPUT + echo "TAG=${{ github.event.release.tag_name }}" >> $env:GITHUB_OUTPUT + } else { + # Get latest release + $latestRelease = gh release list --limit 1 --json tagName,name | ConvertFrom-Json | Where-Object { $_.name -like "EXTENSION_NAME Extension*" } + $version = $latestRelease.tagName -replace "EXTENSION_NAME-v", "" + echo "VERSION=$version" >> $env:GITHUB_OUTPUT + echo "TAG=$($latestRelease.tagName)" >> $env:GITHUB_OUTPUT + } + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install wingetcreate + run: | + iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe + + - name: Update WinGet manifest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + $version = "${{ steps.release.outputs.VERSION }}" + $tag = "${{ steps.release.outputs.TAG }}" + + # URLs for both installers + $x64Url = "https://github.com/GITHUB_USER_NAME/GITHUB_REPO/releases/download/$tag/EXTENSION_NAME-Setup-$version-x64.exe" + $arm64Url = "https://github.com/GITHUB_USER_NAME/GITHUB_REPO/releases/download/$tag/EXTENSION_NAME-Setup-$version-arm64.exe" + + Write-Host "Updating WinGet manifest for version $version" + Write-Host "x64 URL: $x64Url" + Write-Host "ARM64 URL: $arm64Url" + + # Update the manifest with both architecture installers + .\wingetcreate.exe update YOUR_PACKAGE_IDENTITY_NAME_HERE ` + --version $version ` + --urls "$x64Url|x64" "$arm64Url|arm64" ` + --token $env:GITHUB_TOKEN ` + --submit + +``` + + + ## Related content - [Extensibility overview](extensibility-overview.md) From d9d9ce2a50c143f34a13cf5dbe8505eb7cfc93c6 Mon Sep 17 00:00:00 2001 From: chatasweetie Date: Mon, 3 Nov 2025 14:47:42 -0800 Subject: [PATCH 09/13] for gh actions added global variables to make script updating easier, thanks Gleb! --- .../command-palette/publish-extension.md | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index 792d84291a..46483f9545 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -506,13 +506,13 @@ mkdir .github/workflows # # To use this template for a new extension: # 1. Copy this file to a new workflow file (e.g., release-myextension-exe.yml) -# 2. Replace all instances of GITHUB_REPO_URL with your GitHub repository URL (e.g., https://github.com/yourusername/YourRepository) -# 3. Replace all instances of DISPLAY_NAME with your display name (e.g., My Extension) -# 4. Replace all instances of EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) -# 5. Replace all instances of FOLDER_NAME with your project folder name (e.g., CmdPalMyExtension) -# 6. Update the default version in the build script to match your project file +# 2. Update Global constants with your data: +# - GITHUB_REPO_URL with your GitHub repository URL (e.g., https://github.com/yourusername/YourRepository) +# - DISPLAY_NAME with your display name (e.g., My Extension) +# - EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +# - FOLDER_NAME with your project folder name (e.g., CmdPalMyExtension) -name: DISPLAY_NAME - Build EXE Installer +name: CmdPal Extension - Build EXE Installer on: workflow_dispatch: @@ -527,6 +527,15 @@ on: default: 'New release with latest updates and improvements.' type: string + +# Global constants: UPDATE THESE, example; DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'CmdPal Name' }} +env: + DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'DISPLAY_NAME' }} + EXTENSION_NAME: ${{ vars.EXTENSION_NAME || 'EXTENSION_NAME' }} + FOLDER_NAME: ${{ vars.FOLDER_NAME || 'FOLDER_NAME' }} + GITHUB_REPO_URL: ${{ vars.GITHUB_REPO_URL || 'GITHUB_REPO_URL' }} + + jobs: build: runs-on: windows-2022 @@ -631,11 +640,6 @@ This file is a Github Action scrip that does the following: - Upload Results (clear artifact + release steps) 1. Update the placeholders in `release-extension.yml`: - - DEVELOPER_NAME - - GITHUB_REPO_URL - - EXTENSION_NAME - - FOLDER_NAME - - GENERATE-NEW-GUID-HERE 1. git commit the 3 new files: `build-exe.ps1`, `setup.iss`,`release-extension.yml` 1. Push changes to Github. 1. Trigger the GitHub Action: @@ -697,7 +701,7 @@ Check out how [PowerToys](https://github.com/microsoft/PowerToys/blob/main/.gith You can also use the following `.github\workflows\update-winget-randomriddle.yml`: -``` +```yml # Replace EXTENSION_NAME # Replace GITHUB_USER_NAME # Replace GITHUB_REPO @@ -720,6 +724,13 @@ on: required: false type: string +# Global constants: UPDATE THESE, example; DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'CmdPal Name' }} +env: + DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'DISPLAY_NAME' }} + EXTENSION_NAME: ${{ vars.GITHUB_USER_NAME || 'GITHUB_USER_NAME' }} + FOLDER_NAME: ${{ vars.GITHUB_REPO || 'GITHUB_REPO' }} + GITHUB_REPO_URL: ${{ vars.YOUR_PACKAGE_IDENTITY_NAME_HERE || 'YOUR_PACKAGE_IDENTITY_NAME_HERE' }} + jobs: update-winget: # Only run if this is a EXTENSION_NAME release From 4411cc70764bd6e00c58057a87c74866026a4e74 Mon Sep 17 00:00:00 2001 From: chatasweetie Date: Mon, 3 Nov 2025 15:28:33 -0800 Subject: [PATCH 10/13] updated gh actions and ps1 files to use variables at the top of the file, thanks Felipe! --- .../command-palette/publish-extension.md | 84 ++++++++++--------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index 46483f9545..f0cd993993 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -361,25 +361,27 @@ Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; Value # # To use this template for a new extension: # 1. Copy this file to your extension's project folder as "build-exe.ps1" -# 2. Replace EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) -# 3. Replace with your extension version (e.g., 0.0.1.0) -# 4. Update the default version to match your project file's AppxPackageVersion +# 2. Update in param(): +# - EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +# - VERSION with your extension version (e.g., 0.0.1.0) + + param( + [string]$ExtensionName = "UPDATE", # Change to your extension name [string]$Configuration = "Release", - [string]$Version = "", + [string]$Version = "UPDATE", # Change to your version [string]$Platform = @("x64", "arm64") ) $ErrorActionPreference = "Stop" -Write-Host "Building EXTENSION_NAME EXE installer..." -ForegroundColor Green -Write-Host "Version: $Version" -ForegroundColor Yellow +Write-Host "Building $ExtensionName EXE installer..." -ForegroundColor GreenWrite-Host "Version: $Version" -ForegroundColor Yellow Write-Host "Platforms: $($Platforms -join ', ')" -ForegroundColor Yellow $ProjectDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$ProjectFile = "$ProjectDir\EXTENSION_NAME.csproj" +$ProjectFile = "$ProjectDir\$ExtensionName.csproj" # Clean previous builds Write-Host "Cleaning previous builds..." -ForegroundColor Yellow @@ -562,7 +564,7 @@ jobs: if ("${{ github.event.inputs.version }}" -ne "") { $version = "${{ github.event.inputs.version }}" } else { - $projectFile = "FOLDER_NAME/EXTENSION_NAME.csproj" + $projectFile = "${{ env.FOLDER_NAME }}/${{ env.EXTENSION_NAME }}.csproj" $xml = [xml](Get-Content $projectFile) $version = $xml.Project.PropertyGroup.AppxPackageVersion | Select-Object -First 1 if (-not $version) { throw "Version not found in project file" } @@ -573,31 +575,31 @@ jobs: - name: Build EXE installers (x64 and ARM64) run: | - Set-Location "FOLDER_NAME/FOLDER_NAME" + Set-Location "${{ env.FOLDER_NAME }}/${{ env.FOLDER_NAME }}" .\build-exe.ps1 -Version "${{ steps.version.outputs.VERSION }}" -Platforms @("x64", "arm64") shell: pwsh - name: Upload x64 installer artifact uses: actions/upload-artifact@v4 with: - name: EXTENSION_NAME-x64-installer - path: FOLDER_NAME/bin/Release/installer/*-x64.exe + name: ${{ env.EXTENSION_NAME }}-x64-installer + path: ${{ env.FOLDER_NAME }}/bin/Release/installer/*-x64.exe if-no-files-found: error - name: Upload ARM64 installer artifact uses: actions/upload-artifact@v4 with: - name: EXTENSION_NAME-arm64-installer - path: FOLDER_NAME/bin/Release/installer/*-arm64.exe + name: ${{ env.EXTENSION_NAME }}-arm64-installer + path: ${{ env.FOLDER_NAME }}/bin/Release/installer/*-arm64.exe if-no-files-found: warn - name: Create GitHub Release uses: softprops/action-gh-release@v1 with: - tag_name: EXTENSION_NAME-v${{ steps.version.outputs.VERSION }} - name: "DISPLAY_NAME v${{ steps.version.outputs.VERSION }}" + tag_name: ${{ env.EXTENSION_NAME }}-v${{ steps.version.outputs.VERSION }} + name: "${{ env.DISPLAY_NAME }} v${{ steps.version.outputs.VERSION }}" body: | - ## 🎯 DISPLAY_NAME ${{ steps.version.outputs.VERSION }} + ## 🎯 ${{ env.DISPLAY_NAME }} ${{ steps.version.outputs.VERSION }} ## What's New ${{ github.event.inputs.release_notes }} @@ -606,8 +608,8 @@ jobs: Download the installer for your system architecture: - - **x64 (Intel/AMD)**: `DISPLAY_NAME-Setup-${{ steps.version.outputs.VERSION }}-x64.exe` - - **ARM64 (Windows on ARM)**: `DISPLAY_NAME-Setup-${{ steps.version.outputs.VERSION }}-arm64.exe` + - **x64 (Intel/AMD)**: `${{ env.DISPLAY_NAME }}-Setup-${{ steps.version.outputs.VERSION }}-x64.exe` + - **ARM64 (Windows on ARM)**: `${{ env.DISPLAY_NAME }}-Setup-${{ steps.version.outputs.VERSION }}-arm64.exe` 1. Download the appropriate installer from the Assets section below 2. Run the installer with administrator privileges @@ -616,8 +618,8 @@ jobs: ## 🔗 More Information - Repository: GITHUB_REPO_URL - files: FOLDER_NAME/bin/Release/installer/*.exe + Repository: ${{ env.GITHUB_REPO_URL }} + files: ${{ env.FOLDER_NAME }}/bin/Release/installer/*.exe draft: false prerelease: false env: @@ -625,7 +627,7 @@ jobs: - name: Build summary run: | - Write-Host "🎉 DISPLAY_NAME Release Complete!" -ForegroundColor Green + Write-Host "🎉 ${{ env.DISPLAY_NAME }} Release Complete!" -ForegroundColor Green Write-Host "Version: ${{ steps.version.outputs.VERSION }}" -ForegroundColor Yellow Write-Host "📁 Installer uploaded to GitHub Release" -ForegroundColor Green shell: pwsh @@ -699,13 +701,16 @@ You can use GitHub Actions to update your already submitted projects to WinGet. Check out how [PowerToys](https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml) does this. -You can also use the following `.github\workflows\update-winget-randomriddle.yml`: +You can also use the following `.github\workflows\update-winget.yml`: ```yml -# Replace EXTENSION_NAME -# Replace GITHUB_USER_NAME -# Replace GITHUB_REPO -# Repalce YOUR_PACKAGE_IDENTITY_NAME_HERE with the AppxPackageIdentityName located in the .csproj +# To use this template for a new extension: +# 1. Copy this file to a new workflow file (e.g., update-winget.yml) +# 2. Update Environmental variables with your data: +# - GITHUB_REPO with your GitHub repo name +# - GITHUB_REPO with your github user name (e.g., chatasweetie) +# - EXTENSION_NAME with your extension name (e.g., CmdPalMyExtension) +# - YOUR_PACKAGE_IDENTITY_NAME_HERE with the AppxPackageIdentityName located in the .csproj name: Update WinGet - EXTENSION_NAME Extension @@ -724,17 +729,17 @@ on: required: false type: string -# Global constants: UPDATE THESE, example; DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'CmdPal Name' }} +# Global constants: UPDATE THESE, example; EXTENSION_NAME: ${{ vars.EXTENSION_NAME || 'CmdPalMyExtension' }} env: - DISPLAY_NAME: ${{ vars.DISPLAY_NAME || 'DISPLAY_NAME' }} - EXTENSION_NAME: ${{ vars.GITHUB_USER_NAME || 'GITHUB_USER_NAME' }} - FOLDER_NAME: ${{ vars.GITHUB_REPO || 'GITHUB_REPO' }} - GITHUB_REPO_URL: ${{ vars.YOUR_PACKAGE_IDENTITY_NAME_HERE || 'YOUR_PACKAGE_IDENTITY_NAME_HERE' }} + EXTENSION_NAME: ${{ vars.EXTENSION_NAME || 'EXTENSION_NAME' }} + GITHUB_USER_NAME: ${{ vars.GITHUB_USER_NAME || 'GITHUB_USER_NAME' }} + GITHUB_REPO: ${{ vars.GITHUB_REPO || 'GITHUB_REPO' }} + YOUR_PACKAGE_IDENTITY_NAME_HERE: ${{ vars.YOUR_PACKAGE_IDENTITY_NAME_HERE || 'YOUR_PACKAGE_IDENTITY_NAME_HERE' }} jobs: update-winget: - # Only run if this is a EXTENSION_NAME release - if: github.event_name == 'workflow_dispatch' || startsWith(github.event.release.name, 'EXTENSION_NAME Extension') + # Only run if this is a matching extension release + if: github.event_name == 'workflow_dispatch' || startsWith(github.event.release.name, '${{ env.EXTENSION_NAME }} Extension') runs-on: windows-latest steps: - name: Checkout code @@ -749,13 +754,13 @@ jobs: echo "TAG=${{ inputs.release_tag }}" >> $env:GITHUB_OUTPUT } elseif ("${{ github.event_name }}" -eq "release") { # Extract from release event - $version = "${{ github.event.release.tag_name }}" -replace "EXTENSION_NAME-v", "" + $version = "${{ github.event.release.tag_name }}" -replace "${{ env.EXTENSION_NAME }}-v", "" echo "VERSION=$version" >> $env:GITHUB_OUTPUT echo "TAG=${{ github.event.release.tag_name }}" >> $env:GITHUB_OUTPUT } else { # Get latest release - $latestRelease = gh release list --limit 1 --json tagName,name | ConvertFrom-Json | Where-Object { $_.name -like "EXTENSION_NAME Extension*" } - $version = $latestRelease.tagName -replace "EXTENSION_NAME-v", "" + $latestRelease = gh release list --limit 1 --json tagName,name | ConvertFrom-Json | Where-Object { $_.name -like "${{ env.EXTENSION_NAME }} Extension*" } + $version = $latestRelease.tagName -replace "${{ env.EXTENSION_NAME }}-v", "" echo "VERSION=$version" >> $env:GITHUB_OUTPUT echo "TAG=$($latestRelease.tagName)" >> $env:GITHUB_OUTPUT } @@ -774,20 +779,19 @@ jobs: $tag = "${{ steps.release.outputs.TAG }}" # URLs for both installers - $x64Url = "https://github.com/GITHUB_USER_NAME/GITHUB_REPO/releases/download/$tag/EXTENSION_NAME-Setup-$version-x64.exe" - $arm64Url = "https://github.com/GITHUB_USER_NAME/GITHUB_REPO/releases/download/$tag/EXTENSION_NAME-Setup-$version-arm64.exe" + $x64Url = "https://github.com/${{ env.GITHUB_USER_NAME }}/${{ env.GITHUB_REPO }}/releases/download/$tag/${{ env.EXTENSION_NAME }}-Setup-$version-x64.exe" + $arm64Url = "https://github.com/${{ env.GITHUB_USER_NAME }}/${{ env.GITHUB_REPO }}/releases/download/$tag/${{ env.EXTENSION_NAME }}-Setup-$version-arm64.exe" Write-Host "Updating WinGet manifest for version $version" Write-Host "x64 URL: $x64Url" Write-Host "ARM64 URL: $arm64Url" # Update the manifest with both architecture installers - .\wingetcreate.exe update YOUR_PACKAGE_IDENTITY_NAME_HERE ` + .\wingetcreate.exe update ${{ env.YOUR_PACKAGE_IDENTITY_NAME_HERE }} ` --version $version ` --urls "$x64Url|x64" "$arm64Url|arm64" ` --token $env:GITHUB_TOKEN ` --submit - ``` From ba30275d66755eb844d28a3679c898bf497b7381 Mon Sep 17 00:00:00 2001 From: chatasweetie Date: Thu, 6 Nov 2025 11:21:00 -0800 Subject: [PATCH 11/13] changes based on Alvin's review via Learn Authoring Assistant --- .../command-palette/publish-extension.md | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index f0cd993993..b7e9124881 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -9,13 +9,13 @@ no-loc: [PowerToys, Windows, Insider] # Publish Command Palette extensions -This article provides instructions for Command Palette extensions that were created using the Command Palette template. +This article provides instructions for Command Palette extensions that you create with the Command Palette template. You can publish your Command Palette extension through the Microsoft Store, WinGet, or both. This article includes instructions for preparing and publishing your extension to both distribution platforms. ## Microsoft Store -Command Palette extensions can be published to the Microsoft Store. The publishing process is similar to other apps or extensions. You create a new submission in Partner Center and upload your `.msix` package. Command Palette automatically discovers your extension when users install it from the Microsoft Store. +You can publish Command Palette extensions to the Microsoft Store. The publishing process is similar to other apps or extensions. You create a new submission in Partner Center and upload your `.msix` package. Command Palette automatically discovers your extension when users install it from the Microsoft Store. > [!NOTE] > **MSIX packages explained** @@ -61,11 +61,11 @@ Publishing to the Microsoft Store provides your extension with wide reach across ### Set up Microsoft Store -1. Navigate to the [Microsoft Partner Center](https://partner.microsoft.com/dashboard/home). +1. Go to the [Microsoft Partner Center](https://partner.microsoft.com/dashboard/home). 1. Under **Workspaces**, select **Apps and games**. 1. Select **+ New Product**. 1. Select **MSIX or PWA app**. -1. Create a name or reserve a product name. +1. Create or reserve a product name. 1. Start the submission and complete as much as you can until you reach the **Packages** section. 1. In the left navigation, under **Product Management**, select **Product identity**. 1. Copy the following values for use in the next steps: @@ -77,12 +77,12 @@ Publishing to the Microsoft Store provides your extension with wide reach across > - **Package/Identity/Publisher**: `_________________` > - **Package/Properties/PublisherDisplayName**: `_________________` > -> You'll use these exact values in the code examples below. +> Use these exact values in the code examples below. ### Prepare the extension 1. In your IDE, open `\Package.appxmanifest`. -1. Replace the values with the information you copied from Partner Center: +1. Replace the values with the information you copied from Partner Center. ```xml .csproj`. -1. Locate a `PropertyGroup` element (with no conditions) and add the following properties using your Partner Center values: +1. Locate a `PropertyGroup` element (with no conditions) and add the following properties by using your Partner Center values: ```xml YOUR_PACKAGE_IDENTITY_NAME_HERE @@ -106,7 +106,7 @@ Publishing to the Microsoft Store provides your extension with wide reach across 0.0.1.0 ``` -1. Update the ItemGroup for images to get all of them by removing: +1. Update the `ItemGroup` for images to get all of them by removing: ```xml @@ -170,7 +170,7 @@ with ``` > [!NOTE] -> The `AppxPackageDir="AppPackages\x64\"` is needed so that the ARM64 build doesn't overwrite the x64 build +> You need the `AppxPackageDir="AppPackages\x64\"` setting so that the ARM64 build doesn't overwrite the x64 build. 1. Locate the MSIX files: @@ -179,7 +179,7 @@ with ``` > [!TIP] -> If you do not see your MSIX files, try `dir bin\ -Recurse -Filter "*.msix"` +> If you don't see your MSIX files, try `dir bin\ -Recurse -Filter "*.msix"`. 1. Note the locations of the `__x64.msix` and `__arm64.msix` files. @@ -222,8 +222,8 @@ with Verify your MSIX build is ready by checking: -- ✅ You've updated `Package.appxmanifest` with correct Identity and Properties -- ✅ You've updated `.csproj` with AppxPackage properties +- ✅ You updated `Package.appxmanifest` with correct Identity and Properties +- ✅ You updated `.csproj` with AppxPackage properties - ✅ Both x64 and ARM64 MSIX files were built successfully - ✅ The `bundle_mapping.txt` file contains correct paths to both MSIX files - ✅ The `.msixbundle` file was created without errors @@ -233,22 +233,22 @@ If any items are missing or failed, review the build commands and check for erro ### Microsoft Store submission -1. Navigate to the [Microsoft Partner Center](https://partner.microsoft.com/dashboard/home) and open your newly created extension project. +1. Go to the [Microsoft Partner Center](https://partner.microsoft.com/dashboard/home) and open your newly created extension project. 1. In **Packages**, upload the created MSIX bundle. 1. Complete the rest of the submission. The following suggestions can help you: 1. In **Languages supported in packages**, under your supported language (for example, English (United States)), in **Description**, make sure to include ` integrates with the Windows Command Palette to...` - 1. In the left navigation, locate **Supplemental info** and select **Additional Testing Information**. Add instructions about needing Powertoys and Command Palette. Here's an [example](https://github.com/chatasweetie/CmdPalExtensions/blob/main/microsoftStoreResources/TesterInstructions.txt). + 1. In the left navigation, locate **Supplemental info** and select **Additional Testing Information**. Add instructions about needing PowerToys and Command Palette. Here's an [example](https://github.com/chatasweetie/CmdPalExtensions/blob/main/microsoftStoreResources/TesterInstructions.txt). 1. Submit your extension to the store. -After submission, Microsoft will review your extension for certification. Monitor your submission status in Partner Center and check for email notifications about approval. Once approved, your extension will be available in the Microsoft Store within a few hours. +After submission, Microsoft reviews your extension for certification. Monitor your submission status in Partner Center and check for email notifications about approval. Once approved, your extension is available in the Microsoft Store within a few hours. ## WinGet -Publishing packages to WinGet is the recommended way to share your extensions with users. Extension packages that are listed on WinGet can be discovered and installed directly from Command Palette. +To share your extensions with users, publish your packages to WinGet. Users can discover and install extension packages listed on WinGet directly from Command Palette. > [!TIP] > **What is WinGet?** -> WinGet is Microsoft's open-source command-line package manager for Windows. It's similar to package managers like npm or pip, but for Windows applications. Publishing to WinGet allows users to install your extension with a simple `winget install` command and enables automatic discovery within Command Palette. +> WinGet is Microsoft's open-source command-line package manager for Windows. It's similar to package managers like npm or pip, but for Windows applications. When you publish to WinGet, users can install your extension with a simple `winget install` command. It also enables automatic discovery within Command Palette. Before submitting your manifest to WinGet, check the following two requirements: @@ -273,7 +273,7 @@ Dependencies: ## Guide to WinGet publishing -Publishing to WinGet is the recommended distribution method for Command Palette extensions as it enables automatic discovery and installation directly within Command Palette. This guide covers the majority of the WinGet publication process, from preparing your project and creating build scripts to setting up GitHub Actions automation and submitting your first package manifest. You'll learn how to create installer packages, configure automated builds, and navigate the WinGet submission workflow to make your extension easily discoverable and installable for users. +Publishing to WinGet is the recommended distribution method for Command Palette extensions. It enables automatic discovery and installation directly within Command Palette. This guide covers most of the WinGet publication process, from preparing your project and creating build scripts to setting up GitHub Actions automation and submitting your first package manifest. You'll learn how to create installer packages, configure automated builds, and navigate the WinGet submission workflow to make your extension easily discoverable and installable for users. ### Requirements @@ -296,7 +296,7 @@ Publishing to WinGet is the recommended distribution method for Command Palette 1. Locate `CLSID` 1. Open the extension's main `.cs` file (for example, `.cs`). 1. Look for the `[Guid("...")]` attribute above the class declaration. - 1. This GUID is your CLSID - Keep note of this because it will be used in th next step + 1. This GUID is your CLSID - Keep note of this because it will be used in the next step ```csharp // Example from .cs @@ -308,8 +308,8 @@ Publishing to WinGet is the recommended distribution method for Command Palette > **What is a CLSID?** > A CLSID (Class Identifier) is a unique identifier that Windows uses to identify COM (Component Object Model) components. Each Command Palette extension needs a unique CLSID so Windows can properly register and load your extension. This GUID is automatically generated when you create your extension project. -1. Make sure that your in the directory that contains your `.cs` for the next two files being created. -1. Create a `setup-template.iss` file, for a simple extension you can copy and customize the following: +1. Make sure that you're in the directory that contains your `.cs` for the next two files being created. +1. Create a `setup-template.iss` file. For a simple extension, you can copy and customize the following template: **Template: `setup-template.iss`** @@ -352,7 +352,7 @@ Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}"; ValueData: "EXTENSI Root: HKCU; Subkey: "SOFTWARE\Classes\CLSID\{{CLSID-HERE}}\LocalServer32"; ValueData: "{app}\EXTENSION_NAME.exe -RegisterProcessAsComServer" ``` -1. Create a `build-exe.ps1` file, for a simple extension you can copy and customize the following: +1. Create a `build-exe.ps1` file. For a simple extension, you can copy and customize the following template: **Template: `build-exe.ps1`** @@ -469,7 +469,7 @@ Write-Host "`n🎉 Build completed successfully!" -ForegroundColor Green ``` > [!TIP] -> You can test this locally by having [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) and [Inno Setup](https://jrsoftware.org/isdl.php) installed. +> You can test this process locally by installing [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) and [Inno Setup](https://jrsoftware.org/isdl.php) installed. > > ```powershell > # verify .Net 9 is installed @@ -478,7 +478,7 @@ Write-Host "`n🎉 Build completed successfully!" -ForegroundColor Green > # verify Inno Setup is installed > Test-Path "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" > -> # build installer, this will take a while +> # build installer, this step takes a while > .\build-exe.ps1 -Version "0.0.1.0" > > # verify that -Setup-0.0.1.0.exe is listed @@ -491,10 +491,10 @@ Write-Host "`n🎉 Build completed successfully!" -ForegroundColor Green > **What are GitHub Actions?** > GitHub Actions is a CI/CD platform that automates software workflows directly in your GitHub repository. For Command Palette extensions, GitHub Actions can automatically build your installer whenever you push code changes, create releases, and even submit updates to WinGet - eliminating manual build steps and ensuring consistent, reproducible builds. -Now we'll set up GitHub Actions to automate the build and release process: +Now set up GitHub Actions to automate the build and release process: -1. `cd ..` up a directory, you should be in the directory that contains `.sln` -1. create a new repo: +1. Run `cd ..` to go up a directory. You should be in the directory that contains `.sln`. +1. Create a new repo. ```powershell mkdir .github/workflows @@ -633,7 +633,7 @@ jobs: shell: pwsh ``` -This file is a Github Action scrip that does the following: +This file is a GitHub Action script that does the following tasks: - Setup (.NET, Inno Setup) - Get Version (simple version detection) @@ -641,9 +641,9 @@ This file is a Github Action scrip that does the following: - Create Installer (simple Inno Setup call) - Upload Results (clear artifact + release steps) -1. Update the placeholders in `release-extension.yml`: -1. git commit the 3 new files: `build-exe.ps1`, `setup.iss`,`release-extension.yml` -1. Push changes to Github. +1. Update the placeholders in `release-extension.yml`. +1. Commit the three new files: `build-exe.ps1`, `setup.iss`, and `release-extension.yml`. +1. Push changes to GitHub. 1. Trigger the GitHub Action: ```powershell @@ -663,8 +663,7 @@ Verify your GitHub Actions setup by checking: ### WinGet submission > [!IMPORTANT] -> The first submission must be manual. `wingetcreate new` requires interactive input for package details - +> You must manually submit the first version. `wingetcreate new` requires interactive input for package details #### Manual first submission @@ -678,7 +677,7 @@ Verify your GitHub Actions setup by checking: > [!TIP] > To get the GitHub Release URL: Go to your release page, under **Assets**, right-click the `.exe` file and select "Copy link address". -1. When `wingetcreate` prompts you, press **Enter** if the suggested response is pulled from the EXE file, for example: `PackageIdentifier`, `PackageVersion`, `Publisher`, etc. +1. When `wingetcreate` prompts you, press **Enter** if the suggested response is pulled from the EXE file, for example: `PackageIdentifier`, `PackageVersion`, `Publisher`, and so on. - **For optional modification questions**, answer **No**: - "Would you like to modify the optional default locale fields?" → **No** - "Would you like to modify the optional installer fields?" → **No** @@ -686,14 +685,14 @@ Verify your GitHub Actions setup by checking: - **Final submission question**: - "Would you like to submit your manifest to the Windows Package Manager repository?" → **Yes** -After answering "Yes" to submit: +After you answer "Yes" to submit: - `wingetcreate` forks the microsoft/winget-pkgs repository to your GitHub account - Creates a new branch with your package manifests - Opens a pull request automatically - Provides the PR URL for tracking -After submitting your pull request, the WinGet team will review your manifest for compliance and accuracy. You can monitor the PR status on GitHub and respond to any feedback from reviewers. Once approved and merged, your extension will be available through WinGet within a few hours. +After you submit your pull request, the WinGet team reviews your manifest for compliance and accuracy. You can monitor the PR status on GitHub and respond to any feedback from reviewers. Once approved and merged, your extension will be available through WinGet within a few hours. #### WinGet updates via GitHub Actions From cf5d172045b3caeaca57a839971a860b1646b72a Mon Sep 17 00:00:00 2001 From: chatasweetie Date: Thu, 6 Nov 2025 11:35:21 -0800 Subject: [PATCH 12/13] changes based on Niels review --- hub/powertoys/command-palette/publish-extension.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index b7e9124881..392e834012 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -21,7 +21,7 @@ You can publish Command Palette extensions to the Microsoft Store. The publishin > **MSIX packages explained** > MSIX is Microsoft's modern app packaging format that provides secure installation, automatic updates, and clean uninstallation. It replaces older formats like MSI and ensures your extension integrates properly with Windows security and deployment features. -Command Palette can't search for or install extensions that are only listed in the store. You can find those extensions by running the following command: +Command Palette can't search for or install extensions that are only listed in the Store. You can find those extensions by running the following command: ```cmd ms-windows-store://assoc/?Tags=AppExtension-com.microsoft.commandpalette From dec9e9aef8bc17445d8ca320cc508d61448201bd Mon Sep 17 00:00:00 2001 From: chatasweetie Date: Thu, 6 Nov 2025 13:15:02 -0800 Subject: [PATCH 13/13] changes based on Jiri's review --- hub/powertoys/command-palette/publish-extension.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hub/powertoys/command-palette/publish-extension.md b/hub/powertoys/command-palette/publish-extension.md index 392e834012..d7e67c8210 100644 --- a/hub/powertoys/command-palette/publish-extension.md +++ b/hub/powertoys/command-palette/publish-extension.md @@ -46,6 +46,7 @@ Publishing to the Microsoft Store provides your extension with wide reach across - Create all required app icons and ensure they're properly sized ([Create icons using Visual Studio's asset generation tool](../../apps/design/style/iconography/visual-studio-asset-generation)) > [!TIP] +> > - [List of icons and variations](/windows/apps/design/style/iconography/app-icon-construction#complete-list-of-icons-and-variations) > - Make sure you generate the following files: > @@ -86,8 +87,8 @@ Publishing to the Microsoft Store provides your extension with wide reach across ```xml - Publisher="YOUR_PACKAGE_IDENTITY_PUBLISHER_HERE" + Name="YOUR_PACKAGE_IDENTITY_NAME_HERE" + Publisher="YOUR_PACKAGE_IDENTITY_PUBLISHER_HERE" Version="0.0.1.0" /> @@ -213,7 +214,7 @@ with 1. Locate the bundle: ```powershell - ls *.msixbundle + dir *.msixbundle ``` 1. You should find the file: `__Bundle.msixbundle`.