Formatting Output
Note
Learn how to format, display, and export PowerShell output using Format-Table, Format-List, Export-Csv, and other output cmdlets.
Overview
PowerShell gives you powerful tools to control how data is displayed and exported. Whether you're displaying results on screen, saving to files, or sending data to other systems, choosing the right output format is crucial. Remember: format commands should always be last in the pipeline because they convert objects to formatted text.
Critical Rule: Format Last!
Format cmdlets (Format-Table, Format-List, etc.) should always be the last command in a pipeline. They convert objects to formatted display text, which breaks the pipeline for further processing.
Format-Table (Tabular Display)
Display data in columns:
Basic Usage
# Auto-format with default properties
Get-Process | Format-Table
# Specify properties to display
Get-Process | Format-Table Name, CPU, WS
# Auto-size columns (recommended)
Get-Process | Format-Table Name, CPU, WS -AutoSize
# Wrap text that's too long
Get-Service | Format-Table Name, DisplayName -Wrap
Customizing Display
# Group by property
Get-Service | Sort-Object Status | Format-Table -GroupBy Status
# Custom column headers with expressions
Get-Process | Format-Table Name,
@{Label="Memory(MB)";Expression={[math]::Round($_.WS/1MB,2)};Align="Right"},
@{Label="CPU(s)";Expression={[math]::Round($_.CPU,2)};Align="Right"}
# Hide table headers
Get-Process | Format-Table -HideTableHeaders
Real-World Example
# Custom process table
Get-Process | Where-Object {$_.CPU -gt 0} |
Sort-Object CPU -Descending |
Select-Object -First 10 |
Format-Table -AutoSize `
Name,
@{L="PID";E={$_.Id};Align="Right"},
@{L="CPU(s)";E={"{0:N2}" -f $_.CPU};Align="Right"},
@{L="Mem(MB)";E={"{0:N0}" -f ($_.WS/1MB)};Align="Right"},
@{L="Handles";E={$_.Handles};Align="Right"}
Format-List (Detailed Display)
Display properties in a list format (one property per line):
Basic Usage
# Display all properties
Get-Process powershell | Format-List
# Display specific properties
Get-Process powershell | Format-List Name, CPU, WS, StartTime
# Display all properties including hidden ones
Get-Process powershell | Format-List *
When to Use Format-List
# Good for: Single item with many properties
Get-Service Spooler | Format-List *
# Good for: Detailed view of one or few items
Get-ChildItem "C:\Temp\file.txt" | Format-List Name, Length, CreationTime, LastWriteTime
# Bad for: Many items (too verbose)
Get-Process | Format-List # Creates pages of output
Real-World Example
# Detailed service information
Get-Service | Where-Object {$_.Status -eq "Running"} |
Select-Object -First 5 |
Format-List Name,
DisplayName,
Status,
StartType,
@{L="Dependencies";E={$_.ServicesDependedOn.Name -join ", "}}
Format-Wide (Multiple Columns)
Display items in multiple columns:
# Default: single property across multiple columns
Get-Process | Format-Wide Name
# Specify number of columns
Get-ChildItem | Format-Wide Name -Column 4
# Use a property other than Name
Get-Process | Format-Wide -Property Id -Column 5
Format-Custom (Advanced)
Custom formatting using views (advanced):
# Use predefined custom views
Get-Process | Format-Custom -View Priority
# Usually not needed for day-to-day work
Out-GridView (Interactive Table)
Display in a searchable, filterable GUI window:
# Basic grid view
Get-Process | Out-GridView
# With title
Get-Service | Out-GridView -Title "Services on $env:COMPUTERNAME"
# Allow selecting items (returns selected items)
$selected = Get-Process | Out-GridView -PassThru
# User can select items and click OK
# Selected items are returned to $selected
# Multiple selection
$services = Get-Service | Out-GridView -PassThru -Title "Select services to restart"
$services | Restart-Service
Out-GridView Features
- Search: Type in search box to filter
- Column sorting: Click column headers
- Column filtering: Click filter icon, add criteria
- Select items: Use -PassThru to return selections
Export-Csv (Comma-Separated Values)
Export data to CSV files:
# Basic export
Get-Process | Export-Csv -Path "processes.csv"
# Without type information header
Get-Process | Export-Csv -Path "processes.csv" -NoTypeInformation
# Append to existing file
Get-Process | Export-Csv -Path "processes.csv" -Append -NoTypeInformation
# Custom delimiter
Get-Process | Export-Csv -Path "processes.txt" -Delimiter "`t" -NoTypeInformation # Tab-delimited
# Select specific properties first
Get-Process | Select-Object Name, CPU, WS |
Export-Csv -Path "processes.csv" -NoTypeInformation
Import-Csv (Read CSV Files)
# Import CSV
$data = Import-Csv -Path "processes.csv"
# Now you can work with the data
$data | Where-Object {$_.CPU -gt 50}
$data | Sort-Object Name
ConvertTo-Csv / ConvertFrom-Csv
Convert to/from CSV format (in memory, not files):
# Convert to CSV string
$csv = Get-Process | ConvertTo-Csv -NoTypeInformation
# $csv is a string array of CSV data
# Convert from CSV string
$objects = $csv | ConvertFrom-Csv
# Back to objects
Export-Clixml / Import-Clixml
Export objects preserving all properties and types:
# Export (preserves object structure completely)
Get-Process | Export-Clixml -Path "processes.xml"
# Import (recreates original objects)
$processes = Import-Clixml -Path "processes.xml"
$processes | Get-Member # All properties and methods preserved
Use Clixml for PowerShell-to-PowerShell
When saving PowerShell data for later use in PowerShell, use Export-Clixml instead of CSV. It preserves data types, complex objects, and all properties.
ConvertTo-Json / ConvertFrom-Json
Work with JSON format:
# Convert to JSON
$json = Get-Process | Select-Object Name, CPU, WS | ConvertTo-Json
# Pretty-print JSON
$json = Get-Process | Select-Object Name, CPU, WS | ConvertTo-Json -Depth 3
# Convert from JSON
$data = $json | ConvertFrom-Json
$data | Where-Object {$_.CPU -gt 50}
# Export to JSON file
Get-Service | Select-Object Name, Status, StartType |
ConvertTo-Json |
Out-File "services.json"
ConvertTo-Html
Create HTML reports:
# Basic HTML
Get-Process | ConvertTo-Html | Out-File "report.html"
# With custom properties and title
Get-Process | Where-Object {$_.CPU -gt 0} |
Sort-Object CPU -Descending |
Select-Object -First 10 Name, CPU, WS |
ConvertTo-Html -Title "Top 10 Processes" -PreContent "<h1>System Report</h1>" |
Out-File "report.html"
# Open in browser
Invoke-Item "report.html"
Custom HTML with CSS
$css = @"
<style>
body { font-family: Arial; }
table { border-collapse: collapse; width: 100%; }
th { background-color: #4CAF50; color: white; padding: 10px; }
td { border: 1px solid #ddd; padding: 8px; }
tr:nth-child(even) { background-color: #f2f2f2; }
</style>
"@
Get-Service | Where-Object {$_.Status -eq "Running"} |
Select-Object Name, DisplayName, Status |
ConvertTo-Html -Head $css -Title "Running Services" |
Out-File "services.html"
Invoke-Item "services.html"
Out-File
Write output to a text file:
# Basic output
Get-Process | Out-File "processes.txt"
# Append to file
Get-Process | Out-File "processes.txt" -Append
# Specify encoding
Get-Content file.txt | Out-File "output.txt" -Encoding UTF8
# Set width (default is 80 characters)
Get-Process | Format-Table -AutoSize | Out-File "processes.txt" -Width 200
Out-Host (Display on Screen)
Force output to console:
# Paginate output (like more/less)
Get-Process | Out-Host -Paging
# Useful in functions to display progress while returning data
function Get-DataWithProgress {
"Processing..." | Out-Host
Get-Process
}
Out-Null (Discard Output)
Suppress output completely:
# Suppress output (don't display anything)
New-Item "test.txt" -ItemType File | Out-Null
# Useful for commands that return unwanted output
$list = [System.Collections.ArrayList]@()
$list.Add("item") | Out-Null # Suppresses index return value
# Alternative: assign to $null
$null = New-Item "test.txt" -ItemType File
Real-World Examples
Example: Daily Process Report
Scenario: Generate a daily HTML report of top processes
$date = Get-Date -Format "yyyy-MM-dd"
$title = "Process Report - $date"
$css = @"
<style>
body { font-family: 'Segoe UI', Arial; margin: 20px; }
h1 { color: #333; }
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
th { background-color: #0078d4; color: white; padding: 12px; text-align: left; }
td { border: 1px solid #ddd; padding: 10px; }
tr:nth-child(even) { background-color: #f9f9f9; }
tr:hover { background-color: #f5f5f5; }
.warning { color: #d13438; font-weight: bold; }
</style>
"@
# Get top CPU processes
$topCPU = Get-Process | Where-Object {$_.CPU -gt 0} |
Sort-Object CPU -Descending |
Select-Object -First 10 Name,
@{L="CPU(s)";E={"{0:N2}" -f $_.CPU}},
@{L="Memory(MB)";E={"{0:N0}" -f ($_.WS/1MB)}},
@{L="Handles";E={$_.Handles}}
# Get top memory processes
$topMemory = Get-Process |
Sort-Object WS -Descending |
Select-Object -First 10 Name,
@{L="Memory(MB)";E={"{0:N0}" -f ($_.WS/1MB)}},
@{L="CPU(s)";E={"{0:N2}" -f $_.CPU}}
# Build HTML
$html = @"
$css
<h1>$title</h1>
<h2>Top 10 Processes by CPU</h2>
$($topCPU | ConvertTo-Html -Fragment)
<h2>Top 10 Processes by Memory</h2>
$($topMemory | ConvertTo-Html -Fragment)
<p><em>Generated: $(Get-Date)</em></p>
"@
$html | Out-File "ProcessReport_$date.html"
Invoke-Item "ProcessReport_$date.html"
Example: Service Status to Multiple Formats
Scenario: Export service status to CSV, JSON, and HTML
$date = Get-Date -Format "yyyyMMdd_HHmmss"
$outputDir = "C:\Reports"
# Get service data
$services = Get-Service | Select-Object Name, DisplayName, Status, StartType
# Export to CSV
$services | Export-Csv -Path "$outputDir\Services_$date.csv" -NoTypeInformation
# Export to JSON
$services | ConvertTo-Json | Out-File "$outputDir\Services_$date.json"
# Export to HTML
$services | ConvertTo-Html -Title "Service Status Report" |
Out-File "$outputDir\Services_$date.html"
# Display summary
$summary = $services | Group-Object Status | Select-Object Name, Count
Write-Output "`nService Summary:"
$summary | Format-Table -AutoSize
Write-Output "`nReports saved to: $outputDir"
Example: Interactive File Selection
Scenario: Let user select files to process using Out-GridView
# Get all log files
$logFiles = Get-ChildItem -Path C:\Logs -Filter "*.log" -Recurse |
Select-Object Name, FullName,
@{L="SizeMB";E={[math]::Round($_.Length/1MB,2)}},
@{L="Age(Days)";E={((Get-Date) - $_.LastWriteTime).Days}},
LastWriteTime
# Let user select files
$selectedFiles = $logFiles | Out-GridView -Title "Select log files to archive" -PassThru
if ($selectedFiles) {
Write-Output "`nYou selected $($selectedFiles.Count) files"
Write-Output "Total size: $(($selectedFiles | Measure-Object SizeMB -Sum).Sum) MB"
# Process selected files
foreach ($file in $selectedFiles) {
Write-Output "Processing: $($file.Name)"
# Compress or move files here
}
} else {
Write-Output "No files selected"
}
Common Output Patterns
Pattern 1: Data Analysis Report
# Analyze and format
$data = Get-Process
$summary = $data | Measure-Object WS -Sum -Average
$top10 = $data | Sort-Object WS -Descending | Select-Object -First 10
Write-Output "`n===== Process Memory Analysis ====="
Write-Output "Total processes: $($data.Count)"
Write-Output "Total memory: $([math]::Round($summary.Sum/1GB, 2)) GB"
Write-Output "Average memory: $([math]::Round($summary.Average/1MB, 2)) MB"
Write-Output "`nTop 10 by memory:"
$top10 | Format-Table Name, @{L="Memory(MB)";E={[math]::Round($_.WS/1MB,0)}} -AutoSize
Pattern 2: Multi-Format Export
# Get data once
$data = Get-Service | Where-Object {$_.Status -eq "Running"}
# Export to multiple formats
$data | Export-Csv "running_services.csv" -NoTypeInformation
$data | Export-Clixml "running_services.xml"
$data | ConvertTo-Json | Out-File "running_services.json"
$data | ConvertTo-Html | Out-File "running_services.html"
Write-Output "Exported $($data.Count) services to 4 formats"
Pattern 3: Conditional Formatting
# Add visual indicators based on values
Get-Process | Where-Object {$_.CPU -gt 0} |
Select-Object -First 20 Name, CPU,
@{L="MemoryMB";E={[math]::Round($_.WS/1MB,0)}},
@{L="Status";E={
if ($_.CPU -gt 100) { "HIGH CPU" }
elseif ($_.WS -gt 500MB) { "HIGH MEM" }
else { "OK" }
}} |
Sort-Object CPU -Descending |
Format-Table -AutoSize
Tips & Tricks
Always Format Last
Use -AutoSize with Format-Table
Select Properties Before Export
Format Cmdlets Destroy Objects
CSV vs Clixml for PowerShell Data
Out-GridView Requires GUI
Related Topics
- Object Manipulation - Select and transform data before formatting
- The Pipeline - Understanding how format cmdlets affect pipeline
- Functions - Creating functions that output formatted data
- Arrays & Collections - Working with data to format