Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PowerShell pipe to sort fails #2798

Closed
denelon opened this issue Dec 22, 2022 · 5 comments
Closed

PowerShell pipe to sort fails #2798

denelon opened this issue Dec 22, 2022 · 5 comments
Labels
Issue-Bug It either shouldn't be doing this or needs an investigation. PowerShell Issue related to WinGet PowerShell Module or cmdlet
Milestone

Comments

@denelon
Copy link
Contributor

denelon commented Dec 22, 2022

  Here's another example of where the object fails.

image

and this:
image

These break from expected PowerShell behaviors.

Originally posted by @jdhitsolutions in #2796 (comment)

@ghost ghost added the Needs-Triage Issue need to be triaged label Dec 22, 2022
@denelon denelon added Issue-Bug It either shouldn't be doing this or needs an investigation. PowerShell Issue related to WinGet PowerShell Module or cmdlet and removed Needs-Triage Issue need to be triaged labels Dec 22, 2022
@jantari
Copy link

jantari commented Dec 22, 2022

In case someone else finds this, the example Find-WinGetPackage terminal -Source winget | sort id doesn't work because Id isn't actually (directly) a property of the returned objects:

> Find-WinGetPackage terminal -Source winget | gm

   TypeName: Microsoft.Management.Deployment.MatchResult

Name                              MemberType Definition
----                              ---------- ----------
Equals                            Method     bool Equals(Microsoft.Management.Deployment.MatchResult other), bool Equals(System.Object obj), bool IEquatable[MatchResult].Equals(Microsoft.Mana…
GetHashCode                       Method     int GetHashCode()
GetInterface                      Method     System.Runtime.InteropServices.CustomQueryInterfaceResult ICustomQueryInterface.GetInterface([ref] guid iid, [ref] System.IntPtr ppv)
GetInterfaceImplementation        Method     System.RuntimeTypeHandle IDynamicInterfaceCastable.GetInterfaceImplementation(System.RuntimeTypeHandle interfaceType)
GetObjectReferenceForType         Method     WinRT.IObjectReference IWinRTObject.GetObjectReferenceForType(System.RuntimeTypeHandle type)
GetObjectReferenceForTypeFallback Method     WinRT.IObjectReference IWinRTObject.GetObjectReferenceForTypeFallback(System.RuntimeTypeHandle type)
GetOrCreateTypeHelperData         Method     System.Object IWinRTObject.GetOrCreateTypeHelperData(System.RuntimeTypeHandle type, System.Func[System.Object] helperDataFactory)
GetType                           Method     type GetType()
IsInterfaceImplemented            Method     bool IDynamicInterfaceCastable.IsInterfaceImplemented(System.RuntimeTypeHandle interfaceType, bool throwIfNotImplemented)
IsInterfaceImplementedFallback    Method     bool IWinRTObject.IsInterfaceImplementedFallback(System.RuntimeTypeHandle interfaceType, bool throwIfNotImplemented)
ToString                          Method     string ToString()
AdditionalTypeData                Property   System.Collections.Concurrent.ConcurrentDictionary[System.RuntimeTypeHandle,System.Object] AdditionalTypeData {get;}
CatalogPackage                    Property   Microsoft.Management.Deployment.CatalogPackage CatalogPackage {get;}
HasUnwrappableNativeObject        Property   bool HasUnwrappableNativeObject {get;}
MatchCriteria                     Property   Microsoft.Management.Deployment.PackageMatchFilter MatchCriteria {get;}
NativeObject                      Property   WinRT.IObjectReference NativeObject {get;}

The ID is actually in $_.CatalogPackage.Id and the Id property is only shown at formating time. So this works as intended:

Find-WinGetPackage terminal -Source winget | Sort { $_.CatalogPackage.Id }

So really the surprising behavior comes form the Sort-Object cmdlet which apparently just takes any random non-existing Property name to sort on without complaining. I didn't know this either, but you can do stuff like:

ls | sort djk30f9u3f93if # short-form of: Get-ChildItem | Sort-Object -Property djk30f9u3f93if

and it doesn't care. To make this less surprising for users of the Winget module though, maybe PowerShell object ScriptProperty oder CodeProperty can be used. Like scripted formatting values these are dynamically calculated but they still exist as real object properties too and can be accessed and sorted by. They aren't just created at formatting/output time.

@jdhitsolutions
Copy link

The problem is that all of the properties are buried. This is not a user-friendly experience. This is what we are discussing at #2796

@jantari
Copy link

jantari commented Dec 22, 2022

Yes, and it is particularly interesting in the case of the MatchResults returned by Find-WinGetPackage because Get-WinGetPackage actually returns objects with the Id as a more readily accessible property:

Get-WinGetPackage -Source winget | gm

   TypeName: Microsoft.Management.Deployment.CatalogPackage

Name                              MemberType Definition
----                              ---------- ----------
CheckInstalledStatus              Method     Microsoft.Management.Deployment.CheckInstalledStatusResult CheckInstalledStatus(Microsoft.Management.Deployment.InstalledStatusType checkTypes), M…
CheckInstalledStatusAsync         Method     Windows.Foundation.IAsyncOperation[Microsoft.Management.Deployment.CheckInstalledStatusResult] CheckInstalledStatusAsync(Microsoft.Management.Depl…
Equals                            Method     bool Equals(Microsoft.Management.Deployment.CatalogPackage other), bool Equals(System.Object obj), bool IEquatable[CatalogPackage].Equals(Microsof…
GetHashCode                       Method     int GetHashCode()
GetInterface                      Method     System.Runtime.InteropServices.CustomQueryInterfaceResult ICustomQueryInterface.GetInterface([ref] guid iid, [ref] System.IntPtr ppv)
GetInterfaceImplementation        Method     System.RuntimeTypeHandle IDynamicInterfaceCastable.GetInterfaceImplementation(System.RuntimeTypeHandle interfaceType)
GetObjectReferenceForType         Method     WinRT.IObjectReference IWinRTObject.GetObjectReferenceForType(System.RuntimeTypeHandle type)
GetObjectReferenceForTypeFallback Method     WinRT.IObjectReference IWinRTObject.GetObjectReferenceForTypeFallback(System.RuntimeTypeHandle type)
GetOrCreateTypeHelperData         Method     System.Object IWinRTObject.GetOrCreateTypeHelperData(System.RuntimeTypeHandle type, System.Func[System.Object] helperDataFactory)
GetPackageVersionInfo             Method     Microsoft.Management.Deployment.PackageVersionInfo GetPackageVersionInfo(Microsoft.Management.Deployment.PackageVersionId versionKey)
GetType                           Method     type GetType()
IsInterfaceImplemented            Method     bool IDynamicInterfaceCastable.IsInterfaceImplemented(System.RuntimeTypeHandle interfaceType, bool throwIfNotImplemented)
IsInterfaceImplementedFallback    Method     bool IWinRTObject.IsInterfaceImplementedFallback(System.RuntimeTypeHandle interfaceType, bool throwIfNotImplemented)
ToString                          Method     string ToString()
AdditionalTypeData                Property   System.Collections.Concurrent.ConcurrentDictionary[System.RuntimeTypeHandle,System.Object] AdditionalTypeData {get;}
AvailableVersions                 Property   System.Collections.Generic.IReadOnlyList[Microsoft.Management.Deployment.PackageVersionId] AvailableVersions {get;}
DefaultInstallVersion             Property   Microsoft.Management.Deployment.PackageVersionInfo DefaultInstallVersion {get;}
HasUnwrappableNativeObject        Property   bool HasUnwrappableNativeObject {get;}
Id                                Property   string Id {get;}
InstalledVersion                  Property   Microsoft.Management.Deployment.PackageVersionInfo InstalledVersion {get;}
IsUpdateAvailable                 Property   bool IsUpdateAvailable {get;}
Name                              Property   string Name {get;}
NativeObject                      Property   WinRT.IObjectReference NativeObject {get;}

EDIT: well I can see that it makes sense from a technical standpoint, the CatalogPackage property of the MatchResult is the exact same object that Get-WinGetPackage returns after all. So basically MatchResult wraps a CatalogPackage.

I guess if the objects returned from Find-WinGetPackage were just inherited from CatalogPackage but with an additional MatchCriteria property on each that would maybe be more intuitive but I'll have to use this for a few days to really play with it.

@denelon denelon added this to the v1.5-Client milestone Feb 14, 2023
@denelon denelon modified the milestones: v1.5-Client, v.Next-Client Apr 18, 2023
@denelon
Copy link
Contributor Author

denelon commented Apr 22, 2023

We're working on the next preview release. It should be out in the next few days.

We're also getting very close to publishing the "-alpha" version in the PowerShell Gallery.

PowerShell Sort

@denelon denelon modified the milestones: v.Next-Client, v1.5-Client Apr 22, 2023
@denelon
Copy link
Contributor Author

denelon commented Apr 22, 2023

This will be in the next preview release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Bug It either shouldn't be doing this or needs an investigation. PowerShell Issue related to WinGet PowerShell Module or cmdlet
Projects
None yet
Development

No branches or pull requests

3 participants