Advanced functions and pipeline input

PowerShell · Advanced · 14 min

Pipeline-aware functions compose with built-in cmdlets and stream large inputs efficiently.

Adding [CmdletBinding()] above param() turns a function into an advanced function. It gains the common parameters (-Verbose, -ErrorAction, -WhatIf when declared...) and the $PSCmdlet object.

To accept pipeline input, mark a parameter with ValueFromPipeline (the whole object binds) or ValueFromPipelineByPropertyName (a property with the same name, or an [Alias()], binds). The function body is then split into blocks:

  • begin { } runs once before the first item: initialise counters, open connections,
  • process { } runs once per pipeline item, with the parameter bound to that item,
  • end { } runs once at the end: totals, cleanup.

Without a process block the whole body acts like end and only sees the last item. Declare array parameters ([string[]]) and loop inside process, so the function works both when piped and when called with several values directly.

For commands that change things, add [CmdletBinding(SupportsShouldProcess)] and guard changes with if ($PSCmdlet.ShouldProcess($target, 'Delete')) { ... }. Your function then supports -WhatIf and -Confirm automatically, just like Remove-Item. Emit objects with [pscustomobject] rather than formatted text so callers can keep piping.

Example

function Get-FileSizeKB {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [Alias('FullName')]
    [string[]]$Path
  )
  begin   { $total = 0 }
  process {                                  # once per pipeline item
    foreach ($p in $Path) {
      $kb = [math]::Round((Get-Item $p).Length / 1KB, 1)
      $total += $kb
      [pscustomobject]@{ File = Split-Path $p -Leaf; KB = $kb }
    }
  }
  end     { Write-Verbose "total: $total KB" }
}
Get-ChildItem $PSHOME -Filter *.json | Get-FileSizeKB -Verbose   # FullName binds to Path
Get-FileSizeKB -Path (Join-Path $PSHOME 'pwsh.dll')              # direct call

Remember

  • [CmdletBinding()] adds common parameters like -Verbose
  • ValueFromPipeline / ByPropertyName bind piped objects
  • begin once, process per item, end once; SupportsShouldProcess adds -WhatIf

Watch out for

  • Omitting the process block, so a piped function only handles the last item.

Check yourself

  1. A pipeline-aware function has no begin/process/end blocks. What does it see when 5 items are piped in?
  2. What does SupportsShouldProcess give your function?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced

Advanced functions and pipeline input · PowerShell · Topolearn