PowerShell Genie

PowerShell Advanced functions

Adding [CmdletBinding()] above param() turns a plain function into an advanced function. The single line gets you every common parameter for free: -Verbose, -Debug, -ErrorAction, -WarningAction, -ErrorVariable, -OutVariable and more.

Lesson 2 min read Windows PowerShell 5.1 and PowerShell 7

Documentation: Microsoft Learn

Overview

That is what makes Write-Verbose useful. Without [CmdletBinding()] there is no -Verbose switch to turn the messages on. With it, your verbose lines stay silent by default and appear on demand, which is how every built-in cmdlet behaves.

[CmdletBinding(SupportsShouldProcess)] goes further and gives you -WhatIf and -Confirm. Guard the state-changing line with if ($PSCmdlet.ShouldProcess($target)) and callers get a dry run for free. Any function that deletes, stops or overwrites something should have this.

The cost of [CmdletBinding()] is that PowerShell becomes strict about arguments: unknown parameters are now errors rather than being swept into $args. That strictness is the point.

Inspect this example’s structure

Read the command and its supplied arguments. This example requires real PowerShell or its module; this diagram does not execute it.

function Get-BigProcess { [CmdletBinding()] param( [int] $MinimumMB = 200 ) Write-Verbose "Filtering processes above $MinimumMB MB" Get-Process | Where-Object { $_.WorkingSet64 -gt ($MinimumMB * 1MB) } | Select-Object Name, Id, @{ Name = 'WS_MB'; Expression = { [math]::Round($_.WorkingSet64 / 1MB, 1) } } } Get-BigProcess -MinimumMB 400 -Verbose
  1. Stage 1function-MinimumMB -Verbose

    What happens

    [CmdletBinding()] on line 2 is what makes -Verbose on the last line work. Run the call without -Verbose and the Write-Verbose line produces nothing.

    The Select-Object uses a calculated property: a hashtable with Name and Expression keys, where the expression converts bytes to megabytes. That is how you add a column that does not exist on the original object.

    Playbook rule

    Use -WhatIf before destructive cmdlets.

    Add -WhatIf to preview what a destructive cmdlet would do — nothing on your system changes until you run it again without the switch.

    PS> Remove-Item C:\temp\old.log -WhatIf
    What if: Performing the operation "Remove File" on target "C:\temp\old.log".

    Nothing was deleted. -WhatIf only describes the action it would take.

    Worth remembering

    • [CmdletBinding()] adds -Verbose, -ErrorAction and the other common parameters.
    • Write-Verbose only does anything once -Verbose exists.
    • SupportsShouldProcess adds -WhatIf and -Confirm.
    • Unknown parameters become errors instead of landing in $args.

    Primary documentation

    Where-Object reference · Select-Object reference · Get-Process reference

    Try it

    Illustrative output · values vary by environment

    1PS> function Get-BigProcess {
    2PS> [CmdletBinding()]
    3PS> param(
    4PS> [int] $MinimumMB = 200
    5PS> )
    6PS> Write-Verbose "Filtering processes above $MinimumMB MB"
    7PS> Get-Process |
    8PS> Where-Object { $_.WorkingSet64 -gt ($MinimumMB * 1MB) } |
    9PS> Select-Object Name, Id, @{ Name = 'WS_MB'; Expression = { [math]::Round($_.WorkingSet64 / 1MB, 1) } } }
    10PS> Get-BigProcess -MinimumMB 400 -Verbose

    Example reader

    Inspect this page's example

    Fictional browser data when supported

    Run supported commands against the practice data, or inspect the example without executing it.

    Ready to inspect.

      An advanced function using -Verbose and a calculated property.

      Show reference output

      Illustrative output · values vary by environment

      VERBOSE: Filtering processes above 400 MB
      Name     Id     WS_MB
      ----     --     -----
      chrome   9184   464.0
      msedge   7133   521.4

      Keep going

      Next: PowerShell Pipeline binding

      Check your understanding

      Your advanced function removes files. Does adding CmdletBinding alone implement a safe WhatIf path?

      Genie guidePowerShell Advanced functions

      Adding [CmdletBinding()] above param() turns a plain function into an advanced function. The single line gets you every common parameter for free: -Verbose, -Debug, -ErrorAction, -WarningAction, -ErrorVariable, -OutVariable and more.