PowerShell Select-Object: Choose and Shape Output

PowerShell Select-Object: Choose and Shape Output

PowerShell Tips Editor 4 min read
PowerShell Select-Object: Choose and Shape Output

PowerShell cmdlets often return objects with dozens of properties when you only care about three. Displaying a Get-Process result that includes Handles, NPM, PM, WS, CPU, Id, SI, and Name is noisy — you want just Name, CPU, and memory. That’s exactly what PowerShell Select-Object does: it shapes pipeline output by choosing specific properties, computing new ones, limiting result counts, and deduplicating values. This guide covers every practical use.

Quick Answer / TL;DR

# Show only Name and CPU from Get-Process
Get-Process | Select-Object Name, CPU

# Get the top 5 by CPU
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 Name, CPU

Selecting Specific Properties

Pass property names to Select-Object to output only those columns:

# Select a few properties from Get-Process
Get-Process | Select-Object Name, Id, CPU, WorkingSet | Sort-Object CPU -Descending

# Select properties from Get-ChildItem
Get-ChildItem C:\Users\Public\Documents |
    Select-Object Name, Length, LastWriteTime

# Select from Get-Service
Get-Service | Select-Object Name, Status, StartType
Name        Id     CPU WorkingSet
----        --     --- ----------
chrome    4892 1245.3  548732928
vscode    7123  187.2  165429248
pwsh      3456   12.1   87654321

The output object has only the selected properties — the others are discarded. This makes downstream processing faster because fewer properties are carried through the pipeline.

Using -First and -Last to Limit Output

-First N keeps only the first N objects; -Last N keeps only the last N:

# Top 10 memory consumers
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 10

# Last 5 files created (newest)
Get-ChildItem C:\Logs | Sort-Object LastWriteTime | Select-Object -Last 5

# Skip first 10, take next 5 (pagination)
Get-ChildItem C:\Logs | Select-Object -Skip 10 -First 5
Name         WorkingSet
----         ----------
chrome      548732928
outlook     189267968
vscode      165429248
...

Calculated Properties with @{Name=;Expression=}

Add custom computed properties using a hashtable syntax — this is one of the most useful features:

# Add a size in MB column
Get-ChildItem C:\Logs |
    Select-Object Name,
        @{ Name='SizeMB'; Expression={ [math]::Round($_.Length / 1MB, 2) } },
        LastWriteTime

# Add a percentage column for processes
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5 Name,
    @{ Name='MemMB'; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) } },
    @{ Name='CPURounded'; Expression={ [math]::Round($_.CPU, 1) } }
Name        SizeMB LastWriteTime
----        ------ -------------
app.log       2.45 5/4/2026 9:15:22 AM
error.log     0.87 5/4/2026 8:01:05 AM
debug.log     5.12 5/3/2026 11:45:00 PM

The hashtable format is @{ Name='ColumnHeader'; Expression={ script_block } }. Inside the expression, $_ is the current object. You can use N and E as shorthand aliases for Name and Expression.

-ExpandProperty to Unwrap Arrays

-ExpandProperty extracts a single property’s value directly, without creating a wrapper object:

# Regular -Property returns an object with a Name property
Get-Process | Select-Object -Property Name | Get-Member   # Object with .Name

# -ExpandProperty returns the raw string values
$names = Get-Process | Select-Object -ExpandProperty Name
$names[0]     # 'AggregatorHost' — just a string, not a wrapper object

# Practical use: get an array of values for later use
$runningServices = Get-Service |
    Where-Object { $_.Status -eq 'Running' } |
    Select-Object -ExpandProperty Name

$runningServices -join ', '
AggregatorHost
AppInfo, Audiosrv, BFE, BrokerInfrastructure, CDPSvc...

Use -ExpandProperty when you need a flat array of values (like a list of names or IDs) rather than an array of objects. This is essential before using the values as parameters, in SQL queries, or joining into a string.

-Unique for Deduplication

# Get unique file extensions in a folder
Get-ChildItem C:\Users\Public\Documents |
    Select-Object -ExpandProperty Extension |
    Sort-Object -Unique

# Deduplicate objects by a property
Get-EventLog -LogName System -Newest 1000 |
    Select-Object Source -Unique |
    Sort-Object Source
.docx
.pdf
.txt
.xlsx

Select-Object vs Format-Table

A common confusion: both can limit visible columns, but they work very differently:

  • Select-Object — creates new objects with only the chosen properties. Output is still objects, can be piped further, exported to CSV, etc.
  • Format-Table — formats objects as a table for display. Output is formatting instructions, not objects. Do not pipe Format-Table output to other cmdlets that expect objects.
# This works — Select-Object output can be exported
Get-Process | Select-Object Name, CPU | Export-Csv 'C:\Reports\procs.csv' -NoTypeInformation

# This FAILS — Format-Table output cannot be exported as data
Get-Process | Format-Table Name, CPU | Export-Csv 'C:\Reports\procs.csv'   # Wrong!

Common Errors and Fixes

  • -ExpandProperty vs -Property returning different types: Select-Object -Property Name returns an object with a Name property. Select-Object -ExpandProperty Name returns the string itself. If downstream code expects a string but gets an object, switch to -ExpandProperty.
  • Calculated property syntax — easy to get the hashtable wrong: The correct form is @{ Name='Label'; Expression={ $_.Property } }. Common mistakes: forgetting the Name key, using = instead of the key-value format, or forgetting the script block braces around the expression.

Related Cmdlets / See Also

Wrapping Up

Select-Object is the tool for shaping pipeline data: pick only the properties you need, add calculated columns, limit result count, and deduplicate with -Unique. Use -ExpandProperty when you need flat values rather than wrapper objects. Keep objects as objects — don’t use Format-Table until the very end. Your next step: build a process report with calculated columns for memory in MB and export it to CSV.

Send-Item -To