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.


