PowerShell: The basics – Part 5 – Filtering and Formatting

This blog series will teach you the basics of PowerShell. You’ll learn common concepts such as variables, loops, functions and scripts in this series, along with PowerShell unique concepts such as cmdlets, modules and the pipeline.

In this post we will take a brief look at how to filter and format data and objects in PowerShell.

When formatting objects in PowerShell they’re converted into specialized objects for formatting purposes, this means that once an object has been formatted, it loses it’s methods and you can no longer pass it to the pipeline to continue working with it. This means that we should always perform filtering before we format. Formatting is always the last thing you do in the pipeline.

Filtering

Filtering is usually either done in the pipeline by piping the objects to either Where-Object, or Select-Object, but some cmdlets implements a filter parameter where you can specify a custom filter (cmdlets may have different syntaxes for this, so makes sure to look up the specific cmdlet). Another possibility is to utlize the built in Where method in arrays, which can be quite a bit faster than using the pipeline.

Where-Object

When filtering, we use operators and statements which evaluate to either true or false. Only objects that result in a true statement will pass the filter.

# When qualifying by only one property, you can use this syntax
Get-Service | Where-Object -Property Name -eq Spooler
# or
Get-Service | Where-Object Name -eq Spooler

# When you need more complex filtering you pass a scriptblock with one or more statements
Get-Service | Where-Object { $_.Name -like "St*" -and $_.Status -eq 'Running' }

Select-Object

Select-Object is great for selecting a subset of the objects it receives as input. You can also select and transform properties in order to create new objects that only contain the data you want to work with.

# Select only the properties Name and Status, and only include the first 3 objects
Get-Service | Select-Object -Property Name, Status -First 3

# Select only the 3 last objects, with all properties
Get-Service | Select-Object -Last 3

# Transform the status property to values UP/DOWN
Get-Service | Select-Object -Property Name, @{ Name = 'Status'; Expression = { switch ($_.Status) { 'Running' { 'UP' } 'Stopped' { 'DOWN' } } } }

# Select value of only one property
Get-Service | Select-Object -ExpandProperty Name -First 3

# Select only unique object values (if you specify multiple parameters, then the combination of those is what is unique)
Get-Process | Select-Object -Property ProcessName -Unique

# Select all but the 3 first objects
Get-Process | Select-Object -Skip 3

# Select all but the 3 last objects
Get-Process | Select-Object -SkipLast 3

Sort-Object

The Sort-Object cmdlet sorts objects.

# Sort ascending
'apple', 'grapes', 'pineaple', 'banana' | Sort-Object

# Sort descending
'apple', 'grapes', 'pineaple', 'banana' | Sort-Object -Descending

# Sort descending, by property 'Id', and only show unique entries based on property 'Id'
Get-Process | Select-Object -First 5 | Sort-Object -Property Id -Descending

Where Method

Arrays have a method called Where(), which has the benefit of being faster than Where-Object, as it does not rely on the pipeline.

$numbers = 1..10
$numbers.Where({ $_ -gt 5 })
(1..10).Where({ $_ -notin 2, 4, 7 })

The Where method also supports several selection modes. You can find them with the following command:

[System.Management.Automation.WhereOperatorSelectionMode].GetEnumNames()
Selection ModeDescription
DefaultReturn all matches
FirstReturn only first n matches
LastReturn only the last n matches
SkipUntilReturn all after condition is first evaluates to true
Until Return all until condition is true
SplitReturn two arrays, one with matching objects, and one with the rest
# Default
(1..10).Where({ $_ -gt 5 }) # Returns 6..10
(1..10).Where({ $_ -gt 5 }, 'Default') # Returns 6..10

# First
(1..10).Where({ $_ -gt 5 }, 'First') # Returns 6
(1..10).Where({ $_ -gt 5 }, 'First', 2) # Returns 6, 7

# Last
(1..10).Where({ $_ -gt 5 }, 'Last') # Returns 10
(1..10).Where({ $_ -gt 5 }, 'Last', 2) # Returns 9, 10

# SkipUntil
(1..10).Where({ $_ -in 6, 7, 9 }, 'SkipUntil') # Returns 6..10

# Until
(1..10).Where({ $_ -gt 5 }, 'Until') # Returns 1..5

# Split
(1..10).Where({ $_ -gt 5 }, 'Split') # Returns 6..10 (matches), and 1..5 (non-matches)
$highNumbers, $lowNumbers = (1..10).Where({ $_ -gt 5 }, 'Split') # Assign the arrays to variables, matching is first

Formatting

We format output to make the result prettier, or easier to read and understand. However, remember that you should not format objects if you intend to keep working with them, and you should never write functions that format the output, as that should be up to the user to do in the pipeline. Also always perform formatting last, after filtering.

Format-Table

Get-Process | Select-Object -First 5 | Format-Table
# Compact view
Get-Process | Select-Object -First 5 | Format-Table -AutoSize

# Show all properties
Get-Process | Select-Object -First 5 | Format-Table -Property *

# Ensure data is not truncated
Get-Process | Select-Object -First 5 | Format-Table -Wrap

# Group data by property value
Get-Process | Select-Object -First 5 | Format-Table -GroupBy ProcessName

Format-List

Format-List outputs objects, with it’s properties, as a list. This is handy when there are too many properties to view at once in Format-Tablem but the list can quickly become very long, espcially if you include all parameters.

Get-Process | Select-Object -First 3 | Format-List

# Select only properties Id and Name
Get-Process | Select-Object -First 5 | Format-List -Property Id, Name

# Shows all properties
Get-Process | Select-Object -First 5 | Format-List -Property *

# Groups objects by a certain property value
Get-Process | Select-Object -Last 15 | Format-List -GroupBy ProcessName

Out-GridView

Out-GridView is a simple way of creating an interactive table in a separate window. Here you can further filter and sort the results.

Get-Process | Out-GridView

Export/Convert Data

HTML

You can convert objects to HTML, and then optionally export the HTML to a file.

# Convert to HTML code
Get-Process | Select-Object -First 2 | ConvertTo-Html

# Convert to HTML code and export to a file
Get-Process | Select-Object -First 2 | ConvertTo-Html | Out-File Process.html

CSV

CSV is a popular format as it’s compatible with most applications, and it’s easy to work with when you import it back into PowerShell later.

# Convert to CSV
Get-Process | Select-Object -First 2 | ConvertTo-Csv -Delimiter ";" -NoTypeInformation

# Convert to CSV and export to a file
Get-Process | Select-Object -First 2 | Export-Csv -Delimiter ";" -NoTypeInformation -Path Process.csv

JSON

JSON is has become a very popular option for storing data as this is the main data format for Web APIs.

# Convert to JSON
Get-Process | Select-Object -First 2 | ConvertTo-Json -Depth 1

# Convert to JSON and export to a file. Only includes 1 level of parameters, and compresses the output
Get-Process | Select-Object -First 2 | ConvertTo-Json -Depth 1 -Compress | Out-File -FilePath Process.json

XML

XML is an old but still popular format to store data in.

# Convert to XML
Get-Process | Select-Object -First 2 | ConvertTo-Xml

# Convert to XML and export to a file
Get-Process | Select-Object -First 2 | ConvertTo-Xml | Out-File -FilePath Process.xml

Further reading

In the next post we’ll take a look at working with remote computers. If you want more detailed reading on the topics of this post I suggest the following resources:

Leave a Reply