Skip to content

Bring Pinning to PowerShell Cmdlets - #6190

Open
Kaleb Luedtke (Trenly) wants to merge 74 commits into
microsoft:masterfrom
Trenly:PinPlus
Open

Bring Pinning to PowerShell Cmdlets#6190
Kaleb Luedtke (Trenly) wants to merge 74 commits into
microsoft:masterfrom
Trenly:PinPlus

Conversation

@Trenly

@TrenlyKaleb Luedtke (Trenly) commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Bring Pinning to PowerShell Cmdlets

Summary

This PR extends the WinGet pinning system with new metadata, a new CLI subcommand, expanded COM API surface, and PowerShell cmdlets for managing pins.

CLI Changes

  • winget pin add: Added --note argument to attach an optional freeform note to a pin. The timestamp when a pin is created is now recorded automatically.
  • winget pin list --details: New option that displays detailed information about pins for all packages or a specific package (query by ID, name, or keyword).

Pinning Index Schema (v1.1)

  • New schema version adds DateAdded and Note columns to the pin table to persist the new metadata.

COM API (Microsoft.Management.Deployment, contract v30)

  • PackageManager.GetAllPins() — retrieve all pins across all sources.
  • PackageManager.GetPins(CatalogPackage) — retrieve pins for a specific package.
  • PackageManager.PinPackage(CatalogPackage, PinPackageOptions) — add or update a pin.
  • PackageManager.UnpinPackage(CatalogPackage) — remove all pins for a package.
  • PackageManager.ResetAllPins(String sourceName) — reset all pins, optionally scoped to a source.
  • New PackagePin runtime class exposing PackageId, SourceId, Type, GatedVersion, DateAdded, Note, and IsForInstalledPackage.
  • New PinPackageOptions and PinPackageResult runtime classes.
  • New PackagePinType enum (PinnedByManifest, Pinning, Gating, Blocking).

PowerShell (Microsoft.WinGet.Client)

  • Add-WinGetPin — pin a package with a specified pin type, optional gated version, note, and force flag.
  • Get-WinGetPin — list pins, filterable by package/source.
  • Remove-WinGetPin — remove pins for a package.
  • Reset-WinGetPin — reset all pins, optionally scoped to a source.
  • Get-WinGetPackage — new IsPinned property on returned objects.

cc Demitrius Nelon (@denelon) for Naming


Microsoft Reviewers: Open in CodeFlow

@Trenly
Kaleb Luedtke (Trenly) marked this pull request as ready for review April 29, 2026 20:22
@Trenly
Kaleb Luedtke (Trenly) requested a review from a team as a code ownerApril 29, 2026 20:22
@denelon

Copy link
Copy Markdown
Collaborator

Were you able to figure out the PlatyPS MAML stuff for the PowerShell help?

@Trenly

Copy link
Copy Markdown
ContributorAuthor

Were you able to figure out the PlatyPS MAML stuff for the PowerShell help?

Get-Help seems to work the same way for the new cmdlets as it does for the others. I might look at improving the PowerShell help separately in the future. This PR is already bigger than I'm sure John might like it to be, don't want to make anyone too frazzled

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands WinGet’s pinning feature end-to-end (repository schema + CLI workflow + COM/WinRT API + PowerShell cmdlets), adding pin metadata (DateAdded, Note), a new winget pin show command, and PowerShell cmdlets to manage pins.

Changes:

  • Add DateAdded and Note support to the pinning index (schema v1.1) with migration from v1.0.
  • Extend the COM API surface for pin management (get/pin/unpin/reset) and expose PackagePin, PinPackageOptions, PinPackageResult.
  • Add PowerShell cmdlets (Get/Add/Remove/Reset-WinGetPin) and related PS output objects/help.

Reviewed changes

Copilot reviewed 59 out of 59 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/PowerShell/Microsoft.WinGet.Client/ModuleFiles/Microsoft.WinGet.Client.psd1Exports new pin cmdlets from the module.
src/PowerShell/Microsoft.WinGet.Client.Engine/PSObjects/PSPinResult.csAdds PS wrapper for COM pin operation results.
src/PowerShell/Microsoft.WinGet.Client.Engine/PSObjects/PSPackagePin.csAdds PS wrapper for COM PackagePin objects.
src/PowerShell/Microsoft.WinGet.Client.Engine/PSObjects/PSInstalledCatalogPackage.csAdds IsPinned property on installed package output objects.
src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/PackageManagerWrapper.csAdds wrapper methods for new COM pin APIs.
src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/PSEnumHelpers.csAdds conversion helper for PackagePinType.
src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/ManagementDeploymentFactory.csAdds COM factory creation for PinPackageOptions.
src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/ResetPinCommand.csAdds engine command to reset pins via COM.
src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/PinPackageCommand.csAdds engine command to get/add/remove pins via COM.
src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Common/Constants.csAdds parameter sets and noun constant for pin cmdlets.
src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/ResetPinCmdlet.csAdds Reset-WinGetPin cmdlet.
src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RemovePinCmdlet.csAdds Remove-WinGetPin cmdlet (supports pipeline pin input).
src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/PSObjects/PSPackagePinType.csAdds PowerShell-facing enum for pin types.
src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/GetPinCmdlet.csAdds Get-WinGetPin cmdlet.
src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AddPinCmdlet.csAdds Add-WinGetPin cmdlet (type/gatedVersion/note/force).
src/PowerShell/Help/Microsoft.WinGet.Client/Reset-WinGetPin.mdAdds help documentation for reset pin cmdlet.
src/PowerShell/Help/Microsoft.WinGet.Client/Remove-WinGetPin.mdAdds help documentation for remove pin cmdlet.
src/PowerShell/Help/Microsoft.WinGet.Client/Microsoft.WinGet.Client.mdAdds module index entries for new cmdlets.
src/PowerShell/Help/Microsoft.WinGet.Client/Get-WinGetPin.mdAdds help documentation for get pin cmdlet.
src/PowerShell/Help/Microsoft.WinGet.Client/Add-WinGetPin.mdAdds help documentation for add pin cmdlet.
src/Microsoft.Management.Deployment/Public/ComClsids.hAdds CLSIDs for PinPackageOptions activation.
src/Microsoft.Management.Deployment/PinPackageResult.hIntroduces WinRT result type for pin operations.
src/Microsoft.Management.Deployment/PinPackageResult.cppImplements WinRT result type for pin operations.
src/Microsoft.Management.Deployment/PinPackageOptions.hIntroduces WinRT options type for pin operations.
src/Microsoft.Management.Deployment/PinPackageOptions.cppImplements WinRT options type for pin operations.
src/Microsoft.Management.Deployment/PackagePin.hIntroduces WinRT PackagePin runtimeclass.
src/Microsoft.Management.Deployment/PackagePin.cppImplements WinRT PackagePin object creation from internal pins.
src/Microsoft.Management.Deployment/PackageManager.idlAdds pinning APIs + types to the public WinRT contract.
src/Microsoft.Management.Deployment/PackageManager.hDeclares new PackageManager pinning methods.
src/Microsoft.Management.Deployment/PackageManager.cppImplements GetPins/GetAllPins/Pin/Unpin/Reset via pinning data store.
src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxprojAdds new pin-related source/header files to project build.
src/Microsoft.Management.Deployment/Converters.hDeclares GetPinOperationStatus mapping.
src/Microsoft.Management.Deployment/Converters.cppImplements HRESULT→PinResultStatus mapping.
src/Microsoft.Management.Deployment/ComClsids.cppEnables in-proc→out-of-proc redirection for PinPackageOptions.
src/Microsoft.Management.Deployment.Projection/WinGetProjectionFactory.csAdds projection factory method for PinPackageOptions.
src/Microsoft.Management.Deployment.Projection/ClassesDefinition.csRegisters PinPackageOptions class for projection activation.
src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinningIndexInterface_1_1.cppAdds v1.1 pinning schema interface + migration path.
src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinningIndexInterface.hDeclares v1.1 schema interface.
src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinTable.hDeclares v1.1 pin table with new columns.
src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinTable.cppImplements v1.1 pin table CRUD/migration including note/date.
src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_0/PinningIndexInterface_1_0.cppImplements MigrateFrom for v1.0 (not supported).
src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_0/PinningIndexInterface.hAdds MigrateFrom to v1.0 interface declaration.
src/AppInstallerRepositoryCore/Microsoft/Schema/IPinningIndex.hAdds MigrateFrom to schema interface abstraction.
src/AppInstallerRepositoryCore/Microsoft/PinningIndex.hAdds helper to create schema interface for a specific version.
src/AppInstallerRepositoryCore/Microsoft/PinningIndex.cppImplements migration-on-open for pinning index and version dispatch.
src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxprojAdds v1.1 pinning schema files to repository core build.
src/AppInstallerCommonCore/Public/winget/Pin.hAdds DateAdded + Note fields to internal Pin model.
src/AppInstallerCLITests/PinningIndex.cppAdds unit tests for v1.1 schema and migration behavior.
src/AppInstallerCLITests/PinFlow.cppAdds workflow tests for note/date and new pin show behavior.
src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.reswAdds localized strings for --note and pin show output.
src/AppInstallerCLIPackage/Package.appxmanifestRegisters COM server class for PinPackageOptions (dev out-of-proc).
src/AppInstallerCLICore/Workflows/PinFlow.hDeclares new workflow step ShowPinDetails.
src/AppInstallerCLICore/Workflows/PinFlow.cppSets date/note on add; implements winget pin show output filtering.
src/AppInstallerCLICore/Resources.hAdds resource IDs for new pin strings.
src/AppInstallerCLICore/ExecutionArgs.hAdds PinNote execution arg.
src/AppInstallerCLICore/Commands/PinCommand.hAdds PinShowCommand declaration.
src/AppInstallerCLICore/Commands/PinCommand.cppWires up winget pin show and adds --note to pin add.
src/AppInstallerCLICore/Argument.cppAdds CLI argument mapping for --note.
.github/actions/spelling/expect.txtAdds expected spelling words introduced by new tests/log strings.

Comment threadsrc/Microsoft.Management.Deployment/PackageManager.idl Outdated
Comment threadsrc/Microsoft.Management.Deployment/PackageManager.idl Outdated
Comment threadsrc/Microsoft.Management.Deployment/PackageManager.cpp Outdated
Comment threadsrc/AppInstallerCLICore/Workflows/PinFlow.cpp Outdated
Comment threadsrc/AppInstallerCLICore/Workflows/PinFlow.cpp Outdated
Comment threadsrc/AppInstallerCLICore/Commands/PinCommand.cpp Outdated
Comment threadsrc/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw Outdated
Comment threadsrc/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw Outdated
Comment threadsrc/Microsoft.Management.Deployment/PackageManager.cpp Outdated
Comment threadsrc/Microsoft.Management.Deployment/PackageManager.cpp Outdated
Comment threadsrc/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AddPinCmdlet.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 80 out of 80 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (6)

src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RemovePinCmdlet.cs:1

  • Remove-WinGetPin's PinSet parameter set ignores the piped PSPackagePin.SourceId and IsForInstalledPackage, and only uses PackageId to re-resolve a CatalogPackage. This can (a) throw VagueCriteriaException if the same Id exists in multiple sources, and (b) fail entirely for installed-package pins where PackageId is a ProductCode/PFN rather than an available package Id. Fix by using the pin object to disambiguate resolution: when SourceId is present, scope the search to that source; when IsForInstalledPackage is true, resolve via the installed package identity path (or change the engine command to unpin by pin key rather than re-searching). Add a test that pipes a pin from Get-WinGetPin where the package exists in multiple sources and/or covers installed-pin removal.
    src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/PSEnumHelpers.cs:1
  • The default branch throws InvalidOperationException() without a message, which makes user-facing failures (and debugging) opaque when an invalid pin type string flows in. Prefer an exception with a clear message (e.g., ArgumentOutOfRangeException/InvalidOperationException including the invalid value and accepted values).
    src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1:1
  • RemoveTestSource is executed both in the new Describe's AfterAll and again in the file-level AfterAll. If RemoveTestSource is not idempotent, this can make the test suite flaky (second removal fails) and also makes cleanup ordering harder to reason about. Consider removing the nested RemoveTestSource or restructuring so the test source is added/removed in only one place for this file.
    src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1:1
  • RemoveTestSource is executed both in the new Describe's AfterAll and again in the file-level AfterAll. If RemoveTestSource is not idempotent, this can make the test suite flaky (second removal fails) and also makes cleanup ordering harder to reason about. Consider removing the nested RemoveTestSource or restructuring so the test source is added/removed in only one place for this file.
    src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/PinPackageCommand.cs:1
  • This uses async/await and Task.FromResult(...) around a synchronous operation, which creates unnecessary async state machines and makes the flow harder to read. If GetPackageAndExecuteAsync expects a Task<T>, return Task.FromResult(PackageManagerWrapper.Instance.PinPackage(...)) directly (non-async lambda), or if it supports sync delegates, call the sync operation directly.
    src/Microsoft.Management.Deployment/PackageManager.cpp:1
  • GetPins() performs one DB lookup per derived PinKey (pinningData.GetPin(pinKey)), which can become a multi-query pattern for packages with many available versions and/or multiple installed identities. Consider fetching all pins once (GetAllPins) and filtering in-memory by key (e.g., build a hash set of requested keys) or adding a bulk-get API in PinningData/index layer to reduce DB round-trips.

Comment threaddoc/ReleaseNotes.md
Demitrius Nelon (denelon) pushed a commit to denelon/winget-cli that referenced this pull request Jun 17, 2026
- Remove detailed IDL interface definitions (too implementation-level
for a spec; keep high-level description of needed COM surface)
- Use PinType property instead of IsBlocking for future expandability
(supports checking gating pins too)
- Add PR microsoft#6190 (Configuration module improvements) to Resources
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@JohnMcPMSJohnMcPMS left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note for the future, please build things in layers 🥲 :

  1. CLI
  2. COM
  3. PowerShell

That will help with faster reviews and iteration when we can focus on each part.

Comment threadsrc/AppInstallerCLICore/Workflows/PinFlow.cpp
Comment threadsrc/AppInstallerCLICore/Workflows/PinFlow.cpp Outdated
Comment threadsrc/AppInstallerCLITests/PinFlow.cpp Outdated
Comment threadsrc/AppInstallerRepositoryCore/PinningData.cpp
Comment threadsrc/AppInstallerRepositoryCore/Microsoft/PinningIndex.cpp Outdated
addDateAdded.Execute(connection);

StatementBuilder addNote;
addNote.AlterTable(s_PinTable_Table_Name).Add(s_PinTable_Note_Column, Type::Text);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you add multiple columns at once?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing any examples in the codebase where that's done today - perhaps I'm just missing it?

Comment threadsrc/AppInstallerRepositoryCore/Microsoft/PinningIndex.cpp Outdated
@Trenly

Copy link
Copy Markdown
ContributorAuthor
  1. CLI
  2. COM
  3. PowerShell

That will help with faster reviews and iteration when we can focus on each part.

Apprecate the advice and will do for the future (And thank you for your patience with me and my new friend 🤖 )

@JohnMcPMS

Copy link
Copy Markdown
Member

Looking good (sorry about the slow feedback). I'm wondering if we should find some other method to record changes than a single file that commonly produces conflicts.

@Trenly

Copy link
Copy Markdown
ContributorAuthor

Looking good (sorry about the slow feedback). I'm wondering if we should find some other method to record changes than a single file that commonly produces conflicts.

Thats what I've been wondering. . .

@JohnMcPMS

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Trenly@denelon@JohnMcPMS