Skip to content

/glossary/powershell/splatting

What is splatting in PowerShell? (@params instead of $params)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
PowerShell
versions
Windows PowerShell 3.0+, PowerShell 7.x
os
windows, linux, macos

Splatting is passing a collection of parameters to a command in one variable. You build a hashtable whose keys are parameter names and whose values are the arguments, then call the command with @ instead of $ in front of the variable name: Get-ChildItem @params. An array can be splatted too, for positional arguments. It replaces long lines and backtick line continuations, and lets you add parameters conditionally.

Example

powershell
'a', 'b' | ForEach-Object { Set-Content "$_.log" 'x' }
Set-Content notes.txt 'x'
$params = @{
    Path   = '.'
    Filter = '*.log'
    Name   = $true          # a switch parameter: $true turns it on
}
Get-ChildItem @params | Sort-Object
"--- add a parameter in code"
$params.Remove('Filter')
$params['Include'] = '*.txt', '*.log'
$params['Path'] = '.\*'
Get-ChildItem @params | Sort-Object
"--- array splatting (positional)"
$joinArgs = 'C:\data', 'reports'
Join-Path @joinArgs

Output

a.log
b.log
--- add a parameter in code
a.log
b.log
notes.txt
--- array splatting (positional)
C:\data\reports

Notice @params in the call: with $params, PowerShell would pass the hashtable itself as one positional argument.

Rules

RuleDetail
Hashtable keysparameter names without the dash; switch parameters take $true or $false
Array splattingvalues are bound by position, in order
Mix with normal parametersCopy-Item @common -Destination $dst works
Inside a function@PSBoundParameters forwards the parameters your function received to another command
Native programsarray splatting passes each element as an argument: & git @gitArgs

Forward parameters with @PSBoundParameters

powershell
function Get-Logs {
    param([string] $Path = '.', [switch] $Recurse)
    Get-ChildItem -Filter *.log @PSBoundParameters
}

Every parameter the caller passed to Get-Logs is passed on to Get-ChildItem with the same name, so the names must exist on both commands.

Why administrators use it

Microsoft 365 and Active Directory cmdlets often take ten or more parameters. Written on one line, New-MgUser or New-ADUser calls become unreadable, and backtick continuations break as soon as a space follows the backtick. A hashtable puts one parameter per line, can be built from a CSV row, and can be changed before the call: add -WhatIf in a test run, add -Credential only when one was supplied, or remove a parameter that a module version does not support. The same hashtable can be reused for several calls, so shared values such as -Server or -ErrorAction are typed once.

Common mistakes

powershell
function Show-Args {
    [CmdletBinding()]
    param([string] $Name, [int] $Count)
    "Name=$Name Count=$Count"
}
$p = @{ Name = 'report'; Count = 3 }
'--- @p (splatted):'
Show-Args @p
'--- $p (passed as one value):'
Show-Args $p
'--- a key that is not a parameter:'
$bad = @{ Name = 'report'; Size = 3 }
try { Show-Args @bad -ErrorAction Stop } catch { $_.Exception.Message }

Output

--- @p (splatted):
Name=report Count=3
--- $p (passed as one value):
Name=System.Collections.Hashtable Count=0
--- a key that is not a parameter:
A parameter cannot be found that matches parameter name 'Size'.
MistakeWhat happens
$params instead of @paramsthe whole hashtable is bound to the first positional parameter as text
A key that is not a parameter namethe call fails with "A parameter cannot be found that matches parameter name"
Switch written as Recurse = ''use $true or $false; an empty string is not a switch value
Splatting a literal: Cmd @{...}not allowed; assign the hashtable to a variable first
Same parameter in the hashtable and on the lineWindows PowerShell 5.1 fails with "Cannot bind parameter because parameter ... is specified more than once"

The error from a wrong key is explained on A positional parameter cannot be found, which also covers values passed without a parameter name. To make every splatted call stop on errors, include ErrorAction = 'Stop' in the hashtable; see -ErrorAction Stop with try/catch.

FAQ

Can I splat a hashtable literal directly, like Get-ChildItem @{Path='.'}?

No. Splatting works only with a variable name after @. Assign the hashtable to a variable first, then pass @variable.

Does splatting work with native executables such as git or robocopy?

Array splatting does: each element becomes one argument, which avoids quoting problems with spaces. Hashtable splatting is meant for PowerShell commands, because native programs have no named parameters to bind to.

How do I add a switch parameter like -Recurse to a splat?

Use the parameter name as the key and $true as the value, for example Recurse = $true. An empty string fails with Cannot process argument transformation on parameter, because a switch accepts only Boolean values or numbers.

Sources