From 51b06c9c4d50fa96bc5172e145f06b90abc9819b Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Wed, 11 Feb 2026 22:07:34 -0600 Subject: [PATCH] Add filter-by install scope (user/machine) for List and Search Also fix the filter-by source for List to work. Added parameter to Get-WinGetPackage for install scope and pass it down to the filters sent to WinGet CLI. --- doc/ReleaseNotes.md | 71 +++-- .../Commands/ListCommand.cpp | 1 + .../Commands/SearchCommand.cpp | 6 +- .../src/Library/Get-WinGetPackage.ps1 | 274 +++++++++--------- 4 files changed, 186 insertions(+), 166 deletions(-) diff --git a/doc/ReleaseNotes.md b/doc/ReleaseNotes.md index 9d09d35b32..f2495bbf66 100644 --- a/doc/ReleaseNotes.md +++ b/doc/ReleaseNotes.md @@ -1,31 +1,40 @@ -## New in v1.29 - -# New Feature: Source Priority - -> [!NOTE] -> Experimental under `sourcePriority`; defaulted to disabled. - -With this feature, one can assign a numerical priority to sources when added or later through the `source edit` -command. Sources with higher priority are sorted first in the list of sources, which results in them getting put first -in the results if other things are equal. - -> [!TIP] -> Search result ordering in winget is currently based on these values in this order: -> 1. Match quality (how well a valid field matches the search request) -> 2. Match field (which field was matched against the search request) -> 3. Source order (was always relevant, but with priority you can more easily affect this) - -Beyond the ability to slightly affect the result ordering, commands that primarily target available packages -(largely `install`) will now prefer to use a single result from a source with higher priority rather than prompting for -disambiguation from the user. Said another way, if multiple sources return results but only one of those sources has -the highest priority value (and it returned only one result) then that package will be used rather than giving a -"multiple packages were found" error. This has been applied to both winget CLI and PowerShell module commands. - -### REST result match criteria update - -Along with the source priority change, the results from REST sources (like `msstore`) now attempt to correctly set the -match criteria that factor into the result ordering. This will prevent them from being sorted to the top automatically. - -## Bug Fixes - - +## New in v1.29 + +# New Feature: Filter List and Search command by install scope + +This adds the ability to filter the list returned by the `winget list` and `winget search` commands by the install scope +using the `--scope` parameter. Valid scope values are `user` and `machine`. If the parameter is not given, any install +scopes are permitted. + +> [!TIP] +> You can combine parameters for the `--source` and `--scope` parameters when filtering. + +# New Feature: Source Priority + +> [!NOTE] +> Experimental under `sourcePriority`; defaulted to disabled. + +With this feature, one can assign a numerical priority to sources when added or later through the `source edit` +command. Sources with higher priority are sorted first in the list of sources, which results in them getting put first +in the results if other things are equal. + +> [!TIP] +> Search result ordering in winget is currently based on these values in this order: +> 1. Match quality (how well a valid field matches the search request) +> 2. Match field (which field was matched against the search request) +> 3. Source order (was always relevant, but with priority you can more easily affect this) + +Beyond the ability to slightly affect the result ordering, commands that primarily target available packages +(largely `install`) will now prefer to use a single result from a source with higher priority rather than prompting for +disambiguation from the user. Said another way, if multiple sources return results but only one of those sources has +the highest priority value (and it returned only one result) then that package will be used rather than giving a +"multiple packages were found" error. This has been applied to both winget CLI and PowerShell module commands. + +### REST result match criteria update + +Along with the source priority change, the results from REST sources (like `msstore`) now attempt to correctly set the +match criteria that factor into the result ordering. This will prevent them from being sorted to the top automatically. + +## Bug Fixes + +> 1. Prior to this version, it was permitted to provide a `--source` filter for the `winget list` command, however the parameter was ignored. Now if a filter is provided packages will be check before being returned from the `winget list` command. diff --git a/src/AppInstallerCLICore/Commands/ListCommand.cpp b/src/AppInstallerCLICore/Commands/ListCommand.cpp index 334ddb56c9..73689ea771 100644 --- a/src/AppInstallerCLICore/Commands/ListCommand.cpp +++ b/src/AppInstallerCLICore/Commands/ListCommand.cpp @@ -63,6 +63,7 @@ namespace AppInstaller::CLI case Execution::Args::Type::Name: case Execution::Args::Type::Moniker: case Execution::Args::Type::Source: + case Execution::Args::Type::InstallScope: case Execution::Args::Type::Tag: case Execution::Args::Type::Command: context << diff --git a/src/AppInstallerCLICore/Commands/SearchCommand.cpp b/src/AppInstallerCLICore/Commands/SearchCommand.cpp index 0ae547d302..9266e565ec 100644 --- a/src/AppInstallerCLICore/Commands/SearchCommand.cpp +++ b/src/AppInstallerCLICore/Commands/SearchCommand.cpp @@ -22,6 +22,7 @@ namespace AppInstaller::CLI Argument::ForType(Execution::Args::Type::Tag), Argument::ForType(Execution::Args::Type::Command), Argument::ForType(Execution::Args::Type::Source), + Argument{ Execution::Args::Type::InstallScope, Resource::String::InstalledScopeArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help }, Argument::ForType(Execution::Args::Type::Count), Argument::ForType(Execution::Args::Type::Exact), Argument::ForType(Execution::Args::Type::CustomHeader), @@ -59,6 +60,7 @@ namespace AppInstaller::CLI case Execution::Args::Type::Tag: case Execution::Args::Type::Command: case Execution::Args::Type::Source: + case Execution::Args::Type::InstallScope: context << Workflow::CompleteWithSingleSemanticsForValue(valueType); break; @@ -93,10 +95,10 @@ namespace AppInstaller::CLI } else { - context << + context << Workflow::EnsureMatchesFromSearchResult(OperationType::Search) << Workflow::ReportSearchResult; } - + } } diff --git a/tools/PowerShell/Microsoft.WinGet.Client/src/Library/Get-WinGetPackage.ps1 b/tools/PowerShell/Microsoft.WinGet.Client/src/Library/Get-WinGetPackage.ps1 index ec16318108..83b416710f 100644 --- a/tools/PowerShell/Microsoft.WinGet.Client/src/Library/Get-WinGetPackage.ps1 +++ b/tools/PowerShell/Microsoft.WinGet.Client/src/Library/Get-WinGetPackage.ps1 @@ -1,133 +1,141 @@ -Function Get-WinGetPackage{ - <# - .SYNOPSIS - Gets installed packages on the local system. displays the packages installed on the system, as well as whether an update is available. - Additional options can be provided to filter the output, much like the search command. - - .DESCRIPTION - By running this cmdlet with the required inputs, it will retrieve the packages installed on the local system. - - .PARAMETER Filter - Used to search across multiple fields of the package. - - .PARAMETER Id - Used to specify the Id of the package - - .PARAMETER Name - Used to specify the Name of the package - - .PARAMETER Moniker - Used to specify the Moniker of the package - - .PARAMETER Tag - Used to specify the Tag of the package - - .PARAMETER Command - Used to specify the Command of the package - - .PARAMETER Count - Used to specify the maximum number of packages to return - - .PARAMETER Exact - Used to specify an exact match for any parameters provided. Many of the other parameters may be used for case-insensitive substring matches if Exact is not specified. - - .PARAMETER Source - Name of the Windows Package Manager private source. Can be identified by running: "Get-WinGetSource" and using the source Name - - .PARAMETER Header - Used to specify the value to pass as the "Windows-Package-Manager" HTTP header for a REST source. - - .PARAMETER AcceptSourceAgreement - Used to accept any source agreements required by a REST source. - - .EXAMPLE - Get-WinGetPackage -id "Publisher.Package" - - This example expects only a single configured REST source with a package containing "Publisher.Package" as a valid identifier. - - .EXAMPLE - Get-WinGetPackage -id "Publisher.Package" -source "Private" - - This example expects the REST source named "Private" with a package containing "Publisher.Package" as a valid identifier. - - .EXAMPLE - Get-WinGetPackage -Name "Package" - - This example expects the REST source named "Private" with a package containing "Package" as a valid name. - #> - - PARAM( - [Parameter(Position=0)] $Filter, - [Parameter()] $Name, - [Parameter()] $Id, - [Parameter()] $Moniker, - [Parameter()] $Tag, - [Parameter()] $Source, - [Parameter()] $Command, - [Parameter()] [ValidateRange(1, [int]::maxvalue)][int]$Count, - [Parameter()] [switch]$Exact, - [Parameter()] [ValidateLength(1, 1024)]$Header, - [Parameter()] [switch]$AcceptSourceAgreement - ) - BEGIN - { - [string[]] $WinGetArgs = @("List") - [WinGetPackage[]]$Result = @() - [string[]] $IndexTitles = @("Name", "Id", "Version", "Available", "Source") - - if($Filter){ - ## Search across Name, ID, moniker, and tags - $WinGetArgs += $Filter - } - if($PSBoundParameters.ContainsKey('Name')){ - ## Search for the Name - $WinGetArgs += "--Name", $Name.Replace("…", "") - } - if($PSBoundParameters.ContainsKey('Id')){ - ## Search for the ID - $WinGetArgs += "--Id", $Id.Replace("…", "") - } - if($PSBoundParameters.ContainsKey('Moniker')){ - ## Search for the Moniker - $WinGetArgs += "--Moniker", $Moniker.Replace("…", "") - } - if($PSBoundParameters.ContainsKey('Tag')){ - ## Search for the Tag - $WinGetArgs += "--Tag", $Tag.Replace("…", "") - } - if($PSBoundParameters.ContainsKey('Source')){ - ## Search for the Source - $WinGetArgs += "--Source", $Source.Replace("…", "") - } - if($PSBoundParameters.ContainsKey('Count')){ - ## Specify the number of results to return - $WinGetArgs += "--Count", $Count - } - if($Exact){ - ## Search using exact values specified (case-sensitive) - $WinGetArgs += "--Exact" - } - if($PSBoundParameters.ContainsKey('Header')){ - ## Pass the value specified as the Windows-Package-Manager HTTP header - $WinGetArgs += "--header", $Header - } - if($AcceptSourceAgreement){ - ## Accept source agreements - $WinGetArgs += "--accept-source-agreements" - } - } - PROCESS - { - $List = Invoke-WinGetCommand -WinGetArgs $WinGetArgs -IndexTitles $IndexTitles - - foreach ($Obj in $List) { - $Result += [WinGetPackage]::New($Obj) - } - } - END - { - return $Result - } -} - -Export-ModuleMember -Function Get-WinGetPackage \ No newline at end of file +Function Get-WinGetPackage{ + <# + .SYNOPSIS + Gets installed packages on the local system. displays the packages installed on the system, as well as whether an update is available. + Additional options can be provided to filter the output, much like the search command. + + .DESCRIPTION + By running this cmdlet with the required inputs, it will retrieve the packages installed on the local system. + + .PARAMETER Filter + Used to search across multiple fields of the package. + + .PARAMETER Id + Used to specify the Id of the package + + .PARAMETER Name + Used to specify the Name of the package + + .PARAMETER Moniker + Used to specify the Moniker of the package + + .PARAMETER Tag + Used to specify the Tag of the package + + .PARAMETER Command + Used to specify the Command of the package + + .PARAMETER Count + Used to specify the maximum number of packages to return + + .PARAMETER Exact + Used to specify an exact match for any parameters provided. Many of the other parameters may be used for case-insensitive substring matches if Exact is not specified. + + .PARAMETER Source + Name of the Windows Package Manager private source. Can be identified by running: "Get-WinGetSource" and using the source Name + + .PARAMETER Scope + Used to specify the Scope of the Windows Package Manager packages to return. Can be either "User" or "Machine". If not specified, packages from both scopes will be returned. + + .PARAMETER Header + Used to specify the value to pass as the "Windows-Package-Manager" HTTP header for a REST source. + + .PARAMETER AcceptSourceAgreement + Used to accept any source agreements required by a REST source. + + .EXAMPLE + Get-WinGetPackage -id "Publisher.Package" + + This example expects only a single configured REST source with a package containing "Publisher.Package" as a valid identifier. + + .EXAMPLE + Get-WinGetPackage -id "Publisher.Package" -source "Private" + + This example expects the REST source named "Private" with a package containing "Publisher.Package" as a valid identifier. + + .EXAMPLE + Get-WinGetPackage -Name "Package" + + This example expects the REST source named "Private" with a package containing "Package" as a valid name. + #> + + PARAM( + [Parameter(Position=0)] $Filter, + [Parameter()] $Name, + [Parameter()] $Id, + [Parameter()] $Moniker, + [Parameter()] $Tag, + [Parameter()] $Source, + [Parameter()] $Scope, + [Parameter()] $Command, + [Parameter()] [ValidateRange(1, [int]::maxvalue)][int]$Count, + [Parameter()] [switch]$Exact, + [Parameter()] [ValidateLength(1, 1024)]$Header, + [Parameter()] [switch]$AcceptSourceAgreement + ) + BEGIN + { + [string[]] $WinGetArgs = @("List") + [WinGetPackage[]]$Result = @() + [string[]] $IndexTitles = @("Name", "Id", "Version", "Available", "Source") + + if($Filter){ + ## Search across Name, ID, moniker, and tags + $WinGetArgs += $Filter + } + if($PSBoundParameters.ContainsKey('Name')){ + ## Search for the Name + $WinGetArgs += "--Name", $Name.Replace("…", "") + } + if($PSBoundParameters.ContainsKey('Id')){ + ## Search for the ID + $WinGetArgs += "--Id", $Id.Replace("…", "") + } + if($PSBoundParameters.ContainsKey('Moniker')){ + ## Search for the Moniker + $WinGetArgs += "--Moniker", $Moniker.Replace("…", "") + } + if($PSBoundParameters.ContainsKey('Tag')){ + ## Search for the Tag + $WinGetArgs += "--Tag", $Tag.Replace("…", "") + } + if($PSBoundParameters.ContainsKey('Source')){ + ## Search for the Source + $WinGetArgs += "--Source", $Source.Replace("…", "") + } + if($PSBoundParameters.ContainsKey('Scope')){ + ## Search for the Scope + $WinGetArgs += "--Scope", $Scope.Replace("…", "") + } + if($PSBoundParameters.ContainsKey('Count')){ + ## Specify the number of results to return + $WinGetArgs += "--Count", $Count + } + if($Exact){ + ## Search using exact values specified (case-sensitive) + $WinGetArgs += "--Exact" + } + if($PSBoundParameters.ContainsKey('Header')){ + ## Pass the value specified as the Windows-Package-Manager HTTP header + $WinGetArgs += "--header", $Header + } + if($AcceptSourceAgreement){ + ## Accept source agreements + $WinGetArgs += "--accept-source-agreements" + } + } + PROCESS + { + $List = Invoke-WinGetCommand -WinGetArgs $WinGetArgs -IndexTitles $IndexTitles + + foreach ($Obj in $List) { + $Result += [WinGetPackage]::New($Obj) + } + } + END + { + return $Result + } +} + +Export-ModuleMember -Function Get-WinGetPackage