PowerShell Sort-Object: Sort Any Output by Any Property

PowerShell Sort-Object: Sort Any Output by Any Property

PowerShell Tips Editor 4 min read
PowerShell Sort-Object: Sort Any Output by Any Property

Raw cmdlet output comes back in whatever order Windows feels like returning it. That’s fine for a quick look, but for reports, top-N analysis, and any output that humans will read, you need a defined order. PowerShell Sort-Object orders pipeline output by any property — ascending, descending, or by multiple keys in sequence. This guide covers basic sorting, multi-property sorting, stable sort behavior, top-N patterns, and custom sort expressions.

Quick Answer / TL;DR

# Sort services alphabetically
Get-Service | Sort-Object Name

# Sort processes by memory, largest first
Get-Process | Sort-Object WorkingSet -Descending

Basic Sort by Property Name

Pass a property name to Sort-Object to sort by that property ascending:

# Sort files by size (smallest first)
Get-ChildItem C:\Logs | Sort-Object Length

# Sort services alphabetically
Get-Service | Sort-Object Name | Select-Object Name, Status

# Sort by date modified (oldest first)
Get-ChildItem C:\Users\Public\Documents | Sort-Object LastWriteTime
Name              Status
----              ------
AdobeARMservice   Running
AJRouter          Stopped
ALG               Stopped
AppIDSvc          Stopped

The default sort direction is ascending — numbers from smallest to largest, strings alphabetically, dates from oldest to newest. String sorting is case-insensitive by default.

Sorting Descending with -Descending

Add -Descending to reverse the sort order:

# Largest files first
Get-ChildItem C:\Logs -Recurse | Sort-Object Length -Descending |
    Select-Object -First 10 Name, Length

# Most recently modified first
Get-ChildItem C:\Scripts | Sort-Object LastWriteTime -Descending |
    Select-Object -First 5 Name, LastWriteTime

# Highest CPU processes
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 Name, CPU
Name           Length
----           ------
system.log    5242880
app.log       2097152
events.log     524288
debug.log      131072

Sorting by Multiple Properties

Pass an array of property names to sort by primary and secondary keys:

# Sort by Status first, then Name within each status group
Get-Service | Sort-Object Status, Name | Select-Object Name, Status

# Sort by department, then salary descending within department
$employees = @(
    [PSCustomObject]@{ Name='Alice'; Dept='Engineering'; Salary=120000 },
    [PSCustomObject]@{ Name='Bob';   Dept='Marketing';   Salary=95000  },
    [PSCustomObject]@{ Name='Carol'; Dept='Engineering'; Salary=140000 },
    [PSCustomObject]@{ Name='Dave';  Dept='Marketing';   Salary=88000  }
)

$employees | Sort-Object Dept, @{ Expression='Salary'; Descending=$true }
Name  Dept        Salary
----  ----        ------
Carol Engineering 140000
Alice Engineering 120000
Bob   Marketing    95000
Dave  Marketing    88000

For multi-property sort with mixed directions, use hashtable syntax for each property: @{ Expression='PropertyName'; Descending=$true }.

Stable Sort Behavior

PowerShell’s Sort-Object performs a stable sort — items with equal sort key values retain their relative order from the input. This matters when you sort by multiple criteria sequentially:

# Sort by CPU, with ties broken by original order (stable)
Get-Process | Sort-Object CPU -Descending

# In PowerShell 7.0+, Sort-Object is guaranteed stable
# In Windows PowerShell 5.1, it's generally stable but not documented as guaranteed
$PSVersionTable.PSVersion

Sort and Select Top N Results

The most common pattern: sort descending and take the top N:

# Top 10 memory-consuming processes — a quick memory audit
Get-Process |
    Sort-Object WorkingSet -Descending |
    Select-Object -First 10 Name,
        @{ Name='MemMB'; Expression={ [math]::Round($_.WorkingSet/1MB, 1) } } |
    Format-Table -AutoSize

# 5 largest log files
Get-ChildItem C:\Logs -Recurse -File |
    Sort-Object Length -Descending |
    Select-Object -First 5 FullName,
        @{ Name='SizeMB'; Expression={ [math]::Round($_.Length/1MB, 2) } }
Name          MemMB
----          -----
chrome        523.2
outlook       187.4
vscode        157.3
powershell     84.1
explorer       43.7
teams          38.2
sqlservr       35.9
node           27.4
winword        24.8
excel          22.1

Custom Sort Expression

Sort by a computed value rather than a direct property using a script block expression:

# Sort by file extension
Get-ChildItem C:\Users\Public\Documents |
    Sort-Object { $_.Extension.ToLower() } |
    Select-Object Name, Extension

# Sort by string length
'banana', 'apple', 'kiwi', 'blueberry', 'fig' | Sort-Object { $_.Length }

# Sort by calculated date age
Get-ChildItem C:\Logs |
    Sort-Object { (Get-Date) - $_.LastWriteTime } -Descending |
    Select-Object -First 5 Name, LastWriteTime
fig
kiwi
apple
banana
blueberry

Common Errors and Fixes

  • Sorting strings that look like numbers — cast to [int] first: If a property holds the string '10', alphabetic sort makes '10' < '9' because '1' < '9' character by character. Cast the property to [int]: Sort-Object { [int]$_.VersionNumber }.
  • Sort loses type info when piped to Format-Table: Once you pipe to Format-Table, the result is display formatting, not sortable objects. Always sort before formatting: Get-Process | Sort-Object CPU -Descending | Format-Table Name, CPU.

Related Cmdlets / See Also

Wrapping Up

Sort-Object makes any pipeline output readable and analysis-ready. Use -Descending for top-N patterns, pass multiple property names for multi-level sorting, and use hashtable syntax when you need mixed sort directions. Cast string-formatted numbers explicitly before sorting. Your next step: build a memory report using the sort + select top-10 pattern and export it to CSV for review.

Send-Item -To