Tag Archives: pipeline

Great Debate: Pipeline Coding Syles


A good programmer or scripter should always try to produce code that is easy to read and understand. Choosing and consistently applying a strategy for indentation and bracing will make your life, and possibly those of your co-workers, much easier. (Unless, of course, you’re that guy who prides himself in writing code that looks like a cat walked across his keyboard, and cackles any time someone tries to understand it.)

Much of PowerShell’s syntax can borrow coding conventions from C-style languages, but the pipeline is something new. Below are two pipelines formatted a few different ways. Which styles do you find to be the easiest to read? In the second pipeline, which contains an embedded multi-line script block, would your choice be any different if the script block were much longer? For instance, if you couldn’t see both the beginning and the end of the pipeline without scrolling. Do you have another way of formatting these bits of code that you like better?

Remember, there is no right or wrong answer here. The idea is just to generate discussion, and perhaps to help people produce more readable code.

# A simple pipeline with each command fitting on a single line.
# Line breaks after the pipe character.

Get-ChildItem -Path $home\Documents -File |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } |
Select-Object -ExpandProperty Name

Next-Command

# The same pipeline, this time indenting each line after the first one.

Get-ChildItem -Path $home\Documents -File |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } |
    Select-Object -ExpandProperty Name

Next-Command

# This time, using backticks at the end of each line, and placing the 
# pipe character at the beginning of the next line.

Get-ChildItem -Path $home\Documents -File `
| Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } `
| Select-Object -ExpandProperty Name

Next-Command

# And again, with indentation

Get-ChildItem -Path $home\Documents -File `
    | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } `
    | Select-Object -ExpandProperty Name

Next-Command

# A slightly more complex pipeline involving an embedded script block
# passed to ForEach-Object.  Does the pipe symbol after a closing brace,
# potentially much farther down in the code from where the pipeline
# started, change your opinion on what's the easiest to read?

Import-Csv -Path $inputCsvPath |
ForEach-Object {
    # Transform objects in some way
} |
Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

# The same three variations of style involving indentation and backticks:

Import-Csv -Path $inputCsvPath |
    ForEach-Object {
        # Transform objects in some way
    } |
    Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

Import-Csv -Path $inputCsvPath `
| ForEach-Object {
    # Transform objects in some way
} `
| Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

Import-Csv -Path $inputCsvPath `
    | ForEach-Object {
        # Transform objects in some way
    } `
    | Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

Tips on Implementing Pipeline Support


While reviewing Event 1 (and now Event 2) I’ve seen some scripts that don’t quite have the correct pipeline support and others that do a great job with it. Whether it is an unneeded Begin or End statement, or throwing everything into a Process block and not quite getting the expected output or even having a Process block when ValueFromPipeline/ValueFromPipelineByPropertyName is not even enabled. Before I start working through my notes for Event 2, I wanted to get this post out of the way. I hope that what I put together here will help those out who are working to implement pipeline support in their code as well as providing a method of troubleshooting the parameter binding using Trace-Command. The blog post is available here to view.