# Advanced Functions: \`\[CmdletBinding()\]\`

One line, \[CmdletBinding()\] above param(), turns a function into an advanced function that binds its parameters the way a cmdlet does: it refuses a misspelled parameter instead of quietly ignoring it, and gets -Verbose, -ErrorAction and the other common parameters for free.

Journeyman · PowerShell · Updated November 10, 2026

## After this lesson you can

- Make a function advanced with \[CmdletBinding()\], so it gets -Verbose, -ErrorAction and the other common parameters
- Predict how a plain function and an advanced function each handle a misspelled parameter, -Verbose and -ErrorAction

## Key takeaways

- A plain function quietly ignores a parameter it doesn't know, -Verbose and -ErrorAction included.
- [CmdletBinding()] above param() makes an advanced function: a misspelled parameter is an error, as it is for a cmdlet.
- An advanced function gets the common parameters for free. -Verbose shows its Write-Verbose lines, and -ErrorAction reaches the commands inside it.
- Get-Command -Syntax shows [&lt;CommonParameters>] at the end when a function is advanced.

Your `Get-Song` from *Functions: Naming a Job* works when you type it right. Tools get used by people in a hurry, though, and someone will type `Get-Song -Genre Focus` when the parameter is called `-Mood`. A cmdlet would tell them. Your function doesn't, and that's how small mistakes turn into wrong answers nobody notices: a report built from the wrong songs, a cleanup that skipped the folder it was meant for. This lesson adds the one line that makes your function as strict, and as helpful, as a cmdlet.

You need the practice folder and `PlaylistTools.ps1` from *Functions: Naming a Job*. Go to the folder and load the file:

```powershell
Set-Location "$HOME\terminal-practice\playlist-tools"
. .\PlaylistTools.ps1
```

## A plain function lets mistakes slide

Try the misspelled parameter:

```powershell
Get-Song -Genre Focus
```

```text
Title                  Artist         Minutes Mood
-----                  ------         ------- ----
Mile Marker 9          Juniper Kite   4       Upbeat
Gas Station Coffee     The Night Owls 3       Upbeat
Rainy Overpass         Juniper Kite   6       Chill
Backseat Snacks        Maple Street   3       Upbeat
Cruise Control         The Night Owls 5       Chill
Left at the Lighthouse Maple Street   7       Focus
Last Exit Home         Juniper Kite   4       Chill
```

No error, and every song instead of the one Focus song. A plain function puts any parameter it doesn't know on a leftover list and does nothing with it. The parameters every cmdlet has go the same way. Ask it to keep quiet about a missing playlist:

```powershell
Get-Song -Path rock-trip.csv -ErrorAction SilentlyContinue
```

```text
Import-Csv: C:\Users\Sam\terminal-practice\playlist-tools\PlaylistTools.ps1:6
Line |
   6 |      $songs = Import-Csv -Path $Path
     |               ~~~~~~~~~~~~~~~~~~~~~~
     | Could not find file 'C:\Users\Sam\terminal-practice\playlist-tools\rock-trip.csv'.
```

The red text comes anyway: `-ErrorAction` was ignored too.

## One line: \[CmdletBinding()\]

Open `PlaylistTools.ps1` and add `[CmdletBinding()]` (read "cmdlet binding") on the line above `param()`. While you're there, add two `Write-Verbose` lines that say what the function is doing:

```powershell
function Get-Song {
    [CmdletBinding()]
    param(
        [string]$Mood,
        [string]$Path = 'road-trip.csv'
    )
    Write-Verbose "Reading songs from $Path"
    $songs = Import-Csv -Path $Path
    if ($Mood) {
        Write-Verbose "Keeping only the $Mood songs"
        $songs = $songs | Where-Object Mood -eq $Mood
    }
    $songs
}
```

Save, load the file again, and repeat the mistake:

```powershell
. .\PlaylistTools.ps1
Get-Song -Genre Focus
```

```text
Get-Song: A parameter cannot be found that matches parameter name 'Genre'.
```

A function with `[CmdletBinding()]` is an **advanced function**: PowerShell matches its parameters the way it does a cmdlet's, and a name it doesn't know is an error. Any `[Parameter()]` line, such as `[Parameter(Mandatory)]`, makes a function advanced too. You've seen the same line at the top of a script in *Where Output Goes: `Write-Output`, `Write-Host` and Friends*: it works the same way in a script.

## The common parameters, for free

Ask Get-Command how to call Get-Song now:

```powershell
Get-Command Get-Song -Syntax
```

```text
Get-Song [[-Mood] <string>] [[-Path] <string>] [<CommonParameters>]
```

`[<CommonParameters>]` at the end is new. The **common parameters** are the ones every cmdlet has: `-Verbose`, `-ErrorAction`, `-WarningAction`, `-ErrorVariable`, `-OutVariable` and a few more. Once help is installed (*Reading Help: `Get-Help`*), `Get-Help about_CommonParameters` lists them all. Two of them matter most for your tools. `-Verbose` shows your Write-Verbose lines, which stay hidden otherwise:

```powershell
Get-Song -Mood Focus -Verbose
```

```text
VERBOSE: Reading songs from road-trip.csv
VERBOSE: Keeping only the Focus songs

Title                  Artist       Minutes Mood
-----                  ------       ------- ----
Left at the Lighthouse Maple Street 7       Focus
```

And `-ErrorAction` now reaches the commands inside your function, so Import-Csv keeps quiet when you ask it to. The error is still kept in `$Error` (*Reading Errors, and `-ErrorAction`*):

```powershell
Get-Song -Path rock-trip.csv -ErrorAction SilentlyContinue
$Error[0].Exception.Message
```

```text
Could not find file 'C:\Users\Sam\terminal-practice\playlist-tools\rock-trip.csv'.
```

`-ErrorAction Stop` reaches inside the same way, so a `try` and `catch` around your tool sees its errors (*`try`, `catch` and `finally`*). All of this works the same in Windows PowerShell 5.1 and on a Mac or Linux.

**Try it.** Run `Get-Song -Mood Chill -Verbose`, then `Get-Song -Moods Chill`. What does the second one say, and what would the plain function from *Functions: Naming a Job* have done with it?

## Check yourself

2 questions to try on the lesson page.

## So what

Every function you share should start with `[CmdletBinding()]`: it costs one line, catches mistakes a plain function hides, and gives your tool the switches people already know from every cmdlet.

## Key terms

- [Advanced Function](https://www.ask-codey.com/glossary/advanced-function)
- [CmdletBinding](https://www.ask-codey.com/glossary/cmdletbinding)
- [Common Parameters](https://www.ask-codey.com/glossary/common-parameters)
- [ErrorAction](https://www.ask-codey.com/glossary/erroraction)

## Cheat sheets

- [Advanced Functions: \`\[CmdletBinding()\]\`](https://www.ask-codey.com/cheat-sheets/powershell-advanced-functions-cheat-sheet)

## Related

- [Functions: Naming a Job](https://www.ask-codey.com/lessons/powershell-functions)
- [Where Output Goes: \`Write-Output\`, \`Write-Host\` and Friends](https://www.ask-codey.com/lessons/powershell-output-streams)
- [Reading Errors, and \`-ErrorAction\`](https://www.ask-codey.com/lessons/powershell-errors)
- [Checking Input: Validation Attributes](https://www.ask-codey.com/lessons/powershell-parameter-validation)

Source: https://www.ask-codey.com/lessons/powershell-advanced-functions
