Default sort property

PS 5.1 on Win10 1709.

How is the default sort property specified for an object? I’ve googled around and found several copies of the same instance where this question was asked, but either the answer isn’t the answer, or I don’t know what I’m looking at (probability of the latter approaches 100%).

For example,

Get-ChildItem | Sort-Object

sorts on name, even though no sort property was specified.

And the help for Sort-Object says this:

If you do not specify properties, the cmdlet sorts based on default properties for the object type.

The one answer I found for this referred to the FileSystem.Format.ps1xml file, but I don’t see anything in there that relates to sorting and/or ordering. I see that Name is specified as the WideEntry; does sorting also use that by default?

In short, where is Sort getting its information for the default sort property for an object?

Looks like it’s actually stored as part of types.ps1xml, not the FileSystem.Format.ps1xml

“C:\Windows\System32\WindowsPowerShell\v1.0\typesv3.ps1xml”
“C:\Windows\System32\WindowsPowerShell\v1.0\types.ps1xml”

  ‹Type›
    ‹Name›System.IO.DirectoryInfo‹/Name›
    ‹Members›
      ‹CodeProperty›
        ‹Name›Mode‹/Name›
        ‹GetCodeReference›
          ‹TypeName›Microsoft.PowerShell.Commands.FileSystemProvider‹/TypeName›
          ‹MethodName›Mode‹/MethodName›
        ‹/GetCodeReference›
      ‹/CodeProperty›
      ‹ScriptProperty›
        ‹Name›BaseName‹/Name›
        ‹GetScriptBlock›
          $this.Name
        ‹/GetScriptBlock›
      ‹/ScriptProperty›      
      ‹MemberSet›
        ‹Name›PSStandardMembers‹/Name›
        ‹Members›
          ‹NoteProperty›
            ‹Name›DefaultDisplayProperty‹/Name›
            ‹Value›Name‹/Value›
          ‹/NoteProperty›
        ‹/Members›
      ‹/MemberSet›
    ‹/Members›
  ‹/Type›

My apologies for what my wife calls male pattern blindness, but where? In the segment you included, I see only a DefaultDisplayProperty, not a DefaultSortProperty (or anything similar). Nor do I see anything in either of the full .ps1xml files.

Further, on System.IO.FileInfo, e.g., there is no DefaultDisplayProperty, it is instead DefaultDisplayPropertySet and consists of three properties (LastWriteTime,Length,Name), while default sort uses only name. So I don’t see how DefaultDisplayPropertySet could be used as the DefaultSortProperty.

$this.Name

That is the script block for the BaseName ScriptProperty. It’s defining how BaseName is defined for directories (that script block is more elaborate for System.IO.FileInfo). I don’t see how it has anything to do with the default sort property.

Something like this used to trick me up. I’m only sending one property, but sort can’t figure out to sort it (it returns one item), unless I do select -expand or sort -u filename. Maybe open source will fix it.

ls -r *.bat | select-string netsh | select filename | sort -u

This was a fun rabbit hole to go down, but my thought was that this was something defined as a PSStandardMember. This data is hidden by default, so it takes some digging to get which is discussed by Mr. Snover here: PSStandardMembers – The Stealth Property - PowerShell Team

You can see if this is defined in the object like so:

PS C:\Users\Rob> $obj.PSStandardMembers.DefaultKeyPropertySet


ReferencedPropertyNames : {Age, Name}
MemberType              : PropertySet
Value                   : DefaultKeyPropertySet {Age, Name}
TypeNameOfValue         : System.Management.Automation.PSPropertySet
Name                    : DefaultKeyPropertySet
IsInstance              : True

ReferencedPropertyNames : {Age, Name}
MemberType              : PropertySet
Value                   : DefaultKeyPropertySet {Age, Name}
TypeNameOfValue         : System.Management.Automation.PSPropertySet
Name                    : DefaultKeyPropertySet
IsInstance              : True

ReferencedPropertyNames : {Age, Name}
MemberType              : PropertySet
Value                   : DefaultKeyPropertySet {Age, Name}
TypeNameOfValue         : System.Management.Automation.PSPropertySet
Name                    : DefaultKeyPropertySet
IsInstance              : True

You can also use the same method of setting the DefaultKeyPropertySet (default sort) as DefaultDisplayPropertySet:

#Create data to play with
$obj = @()
$obj += [pscustomobject]@{Name = "Alice";Age = '23';Hobby='Football'}
$obj += [pscustomobject]@{Name = "Jim";Age = '19';Hobby='Pool'}
$obj += [pscustomobject]@{Name = "Sam";Age = '29';Hobby='Curling'}

#Define Sort by Age then Name
$defaultSort = @('Age', 'Name')
#Define default properties to show in object (hide Hobby)
$defaultProperties = @('Name', 'Age')

#Define the DefaultKeyPropertySet: https://stackoverflow.com/questions/46715431/how-to-access-psobject-defaultkeypropertyset-details-in-net-with-c-sharp
$defaultSortSet = New-Object System.Management.Automation.PSPropertySet('DefaultKeyPropertySet',[string[]]$defaultSort)
#Lots of blogs on this, setting the default displayed properties
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultProperties)

#Add the PSStandardMembers
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet,$defaultSortSet)

$obj | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers

#Show the PSStandardMembers of the object: https://blogs.msdn.microsoft.com/powershell/2010/02/18/psstandardmembers-the-stealth-property
$obj |Get-Member PSStandardMembers -Force

#   TypeName: System.Management.Automation.PSCustomObject

#Name              MemberType Definition                                                          
#----              ---------- ----------                                                          
#PSStandardMembers MemberSet  PSStandardMembers {DefaultDisplayPropertySet, DefaultKeyPropertySet}

#Object show ordered as order of creation
$obj

#Name  Age
#----  ---
#Alice 23 
#Jim   19 
#Sam   29


#Default sorted by Age
$obj | Sort

#Name  Age
#----  ---
#Jim   19 
#Alice 23 
#Sam   29


#Override default sort by defining property Name
$obj | Sort -Property Name

#Name  Age
#----  ---
#Alice 23 
#Jim   19 
#Sam   29 

If anyone is looking for a good blog idea, I was working on how to enumerate all PSStandardMembers and what other fun could be had.

I hate to be a broken record, but…

The DefaultDisplayProperty[Set] is visible in the types.ps1xml file. We’ve already seen it (Curtis’ post above). (It is nice to know that there’s a PS way to see that information as well, so thanks for that.)

However, neither of those have anything to do with the default sort property (which, from your reply, would seem to be DefaultKeyProperty[Set]). That doesn’t exist in the types.ps1xml file (for either FileInfo or DirectoryInfo; the only occurrence is for HistoryInfo).

In your first block above, you don’t show what $obj is, so we don’t know what object it’s showing the DefaultKeyPropertSet for, but it doesn’t appear to be for Get-ChildItem, at least from my testing.

PS C:\users\vrice\Downloads> $obj = get-childitem .\epm.exe
PS C:\users\vrice\Downloads> $obj


    Directory: C:\users\vrice\Downloads


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        11/1/2017   3:24 PM       38025088 epm.exe


PS C:\users\vrice\Downloads> $obj.PSStandardMembers.DefaultKeyProperty
PS C:\users\vrice\Downloads> $obj.PSStandardMembers.DefaultKeyPropertySet
PS C:\users\vrice\Downloads>

And yet Get-ChildItem sorts automatically on name.

We’re still not at the bottom of the rabbit hole. :slight_smile: