/glossary/powershell/splatting
What is splatting in PowerShell? (@params instead of $params)
- 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
'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 @joinArgsOutput
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
| Rule | Detail |
|---|---|
| Hashtable keys | parameter names without the dash; switch parameters take $true or $false |
| Array splatting | values are bound by position, in order |
| Mix with normal parameters | Copy-Item @common -Destination $dst works |
| Inside a function | @PSBoundParameters forwards the parameters your function received to another command |
| Native programs | array splatting passes each element as an argument: & git @gitArgs |
Forward parameters with @PSBoundParameters
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
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'.
| Mistake | What happens |
|---|---|
| $params instead of @params | the whole hashtable is bound to the first positional parameter as text |
| A key that is not a parameter name | the 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 line | Windows 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.