Bring Pinning to PowerShell Cmdlets#6190
Conversation
|
Were you able to figure out the PlatyPS MAML stuff for the PowerShell help? |
|
There was a problem hiding this comment.
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
DateAddedandNotesupport 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
| File | Description |
|---|---|
| src/PowerShell/Microsoft.WinGet.Client/ModuleFiles/Microsoft.WinGet.Client.psd1 | Exports new pin cmdlets from the module. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/PSObjects/PSPinResult.cs | Adds PS wrapper for COM pin operation results. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/PSObjects/PSPackagePin.cs | Adds PS wrapper for COM PackagePin objects. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/PSObjects/PSInstalledCatalogPackage.cs | Adds IsPinned property on installed package output objects. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/PackageManagerWrapper.cs | Adds wrapper methods for new COM pin APIs. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/PSEnumHelpers.cs | Adds conversion helper for PackagePinType. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/ManagementDeploymentFactory.cs | Adds COM factory creation for PinPackageOptions. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/ResetPinCommand.cs | Adds engine command to reset pins via COM. |
| src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/PinPackageCommand.cs | Adds engine command to get/add/remove pins via COM. |
| src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Common/Constants.cs | Adds parameter sets and noun constant for pin cmdlets. |
| src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/ResetPinCmdlet.cs | Adds Reset-WinGetPin cmdlet. |
| src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RemovePinCmdlet.cs | Adds Remove-WinGetPin cmdlet (supports pipeline pin input). |
| src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/PSObjects/PSPackagePinType.cs | Adds PowerShell-facing enum for pin types. |
| src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/GetPinCmdlet.cs | Adds Get-WinGetPin cmdlet. |
| src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AddPinCmdlet.cs | Adds Add-WinGetPin cmdlet (type/gatedVersion/note/force). |
| src/PowerShell/Help/Microsoft.WinGet.Client/Reset-WinGetPin.md | Adds help documentation for reset pin cmdlet. |
| src/PowerShell/Help/Microsoft.WinGet.Client/Remove-WinGetPin.md | Adds help documentation for remove pin cmdlet. |
| src/PowerShell/Help/Microsoft.WinGet.Client/Microsoft.WinGet.Client.md | Adds module index entries for new cmdlets. |
| src/PowerShell/Help/Microsoft.WinGet.Client/Get-WinGetPin.md | Adds help documentation for get pin cmdlet. |
| src/PowerShell/Help/Microsoft.WinGet.Client/Add-WinGetPin.md | Adds help documentation for add pin cmdlet. |
| src/Microsoft.Management.Deployment/Public/ComClsids.h | Adds CLSIDs for PinPackageOptions activation. |
| src/Microsoft.Management.Deployment/PinPackageResult.h | Introduces WinRT result type for pin operations. |
| src/Microsoft.Management.Deployment/PinPackageResult.cpp | Implements WinRT result type for pin operations. |
| src/Microsoft.Management.Deployment/PinPackageOptions.h | Introduces WinRT options type for pin operations. |
| src/Microsoft.Management.Deployment/PinPackageOptions.cpp | Implements WinRT options type for pin operations. |
| src/Microsoft.Management.Deployment/PackagePin.h | Introduces WinRT PackagePin runtimeclass. |
| src/Microsoft.Management.Deployment/PackagePin.cpp | Implements WinRT PackagePin object creation from internal pins. |
| src/Microsoft.Management.Deployment/PackageManager.idl | Adds pinning APIs + types to the public WinRT contract. |
| src/Microsoft.Management.Deployment/PackageManager.h | Declares new PackageManager pinning methods. |
| src/Microsoft.Management.Deployment/PackageManager.cpp | Implements GetPins/GetAllPins/Pin/Unpin/Reset via pinning data store. |
| src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj | Adds new pin-related source/header files to project build. |
| src/Microsoft.Management.Deployment/Converters.h | Declares GetPinOperationStatus mapping. |
| src/Microsoft.Management.Deployment/Converters.cpp | Implements HRESULT→PinResultStatus mapping. |
| src/Microsoft.Management.Deployment/ComClsids.cpp | Enables in-proc→out-of-proc redirection for PinPackageOptions. |
| src/Microsoft.Management.Deployment.Projection/WinGetProjectionFactory.cs | Adds projection factory method for PinPackageOptions. |
| src/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs | Registers PinPackageOptions class for projection activation. |
| src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinningIndexInterface_1_1.cpp | Adds v1.1 pinning schema interface + migration path. |
| src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinningIndexInterface.h | Declares v1.1 schema interface. |
| src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinTable.h | Declares v1.1 pin table with new columns. |
| src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_1/PinTable.cpp | Implements v1.1 pin table CRUD/migration including note/date. |
| src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_0/PinningIndexInterface_1_0.cpp | Implements MigrateFrom for v1.0 (not supported). |
| src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_0/PinningIndexInterface.h | Adds MigrateFrom to v1.0 interface declaration. |
| src/AppInstallerRepositoryCore/Microsoft/Schema/IPinningIndex.h | Adds MigrateFrom to schema interface abstraction. |
| src/AppInstallerRepositoryCore/Microsoft/PinningIndex.h | Adds helper to create schema interface for a specific version. |
| src/AppInstallerRepositoryCore/Microsoft/PinningIndex.cpp | Implements migration-on-open for pinning index and version dispatch. |
| src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj | Adds v1.1 pinning schema files to repository core build. |
| src/AppInstallerCommonCore/Public/winget/Pin.h | Adds DateAdded + Note fields to internal Pin model. |
| src/AppInstallerCLITests/PinningIndex.cpp | Adds unit tests for v1.1 schema and migration behavior. |
| src/AppInstallerCLITests/PinFlow.cpp | Adds workflow tests for note/date and new pin show behavior. |
| src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw | Adds localized strings for --note and pin show output. |
| src/AppInstallerCLIPackage/Package.appxmanifest | Registers COM server class for PinPackageOptions (dev out-of-proc). |
| src/AppInstallerCLICore/Workflows/PinFlow.h | Declares new workflow step ShowPinDetails. |
| src/AppInstallerCLICore/Workflows/PinFlow.cpp | Sets date/note on add; implements winget pin show output filtering. |
| src/AppInstallerCLICore/Resources.h | Adds resource IDs for new pin strings. |
| src/AppInstallerCLICore/ExecutionArgs.h | Adds PinNote execution arg. |
| src/AppInstallerCLICore/Commands/PinCommand.h | Adds PinShowCommand declaration. |
| src/AppInstallerCLICore/Commands/PinCommand.cpp | Wires up winget pin show and adds --note to pin add. |
| src/AppInstallerCLICore/Argument.cpp | Adds CLI argument mapping for --note. |
| .github/actions/spelling/expect.txt | Adds expected spelling words introduced by new tests/log strings. |
JohnMcPMS
left a comment
There was a problem hiding this comment.
I would like to see the PinTable stuff be thought through more to re-use code in a way that allows the 1.0 code to stay largely untouched and 1.0 to leverage it without anything over.
| /// </summary> | ||
| protected override void ProcessRecord() | ||
| { | ||
| if (this.Blocking && !string.IsNullOrEmpty(this.GatedVersion)) |
There was a problem hiding this comment.
Can we do this through parameter sets? Not sure if it is more complicated or by how much, but it would better integrate with PS (at least I assume that once it has decided which set you are using on the shell it won't offer tab-suggestions from the other sets).
There was a problem hiding this comment.
I took a look and didn't see an easy way to do that using parameter sets. I'll keep digging though
|
Will address the comments in a few days - been super busy; @JohnMcPMS - Assuming this will go in vNext, does that mean I should then be bumping to the next contract version? |
Yes, it should move to 30 as we are branching the 1.29 RC imminently. |
There was a problem hiding this comment.
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'sPinSetparameter set ignores the pipedPSPackagePin.SourceIdandIsForInstalledPackage, and only usesPackageIdto re-resolve aCatalogPackage. This can (a) throwVagueCriteriaExceptionif the same Id exists in multiple sources, and (b) fail entirely for installed-package pins wherePackageIdis a ProductCode/PFN rather than an available package Id. Fix by using the pin object to disambiguate resolution: whenSourceIdis present, scope the search to that source; whenIsForInstalledPackageis 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 fromGet-WinGetPinwhere 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/InvalidOperationExceptionincluding the invalid value and accepted values).
src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1:1 RemoveTestSourceis executed both in the newDescribe'sAfterAlland again in the file-levelAfterAll. IfRemoveTestSourceis not idempotent, this can make the test suite flaky (second removal fails) and also makes cleanup ordering harder to reason about. Consider removing the nestedRemoveTestSourceor restructuring so the test source is added/removed in only one place for this file.
src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1:1RemoveTestSourceis executed both in the newDescribe'sAfterAlland again in the file-levelAfterAll. IfRemoveTestSourceis not idempotent, this can make the test suite flaky (second removal fails) and also makes cleanup ordering harder to reason about. Consider removing the nestedRemoveTestSourceor 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/awaitandTask.FromResult(...)around a synchronous operation, which creates unnecessary async state machines and makes the flow harder to read. IfGetPackageAndExecuteAsyncexpects aTask<T>, returnTask.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 derivedPinKey(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 inPinningData/index layer to reduce DB round-trips.
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--noteargument 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)
DateAddedandNotecolumns 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.PackagePinruntime class exposingPackageId,SourceId,Type,GatedVersion,DateAdded,Note, andIsForInstalledPackage.PinPackageOptionsandPinPackageResultruntime classes.PackagePinTypeenum (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— newIsPinnedproperty on returned objects.cc @denelon for Naming
Microsoft Reviewers: Open in CodeFlow