PowerShell Splatting: Pass Parameters Cleanly

A command with ten parameters crammed onto a single line is nearly impossible to read, review in a pull request, or maintain six months later. PowerShell splatting solves this by storing parameter names and values in a hashtable or array and passing the whole collection to a command with the @ sigil instead of $. The result is clean, readable code that is also easier to build dynamically at runtime. This post covers hashtable splatting, array splatting, dynamic parameter construction, and the powerful $PSBoundParameters pattern.
Basic Hashtable Splatting with @
Store named parameters in a hashtable, then pass the hashtable to a command using @VariableName (not $VariableName). PowerShell maps each hashtable key to the matching parameter name at call time.
# Without splatting — hard to read
Send-MailMessage -From "[email protected]" -To "[email protected]" -Subject "Disk Alert" -Body "Low disk space on Server01" -SmtpServer "smtp.corp.com" -Port 587 -UseSsl
# With splatting — readable
$mailParams = @{
From = "[email protected]"
To = "[email protected]"
Subject = "Disk Alert"
Body = "Low disk space on Server01"
SmtpServer = "smtp.corp.com"
Port = 587
UseSsl = $true
}
Send-MailMessage @mailParams
Array Splatting for Positional Parameters
Array splatting passes values positionally rather than by name. Use this for cmdlets where you want to pass several positional arguments stored in an array variable:
$copyArgs = @(
"C:\Logs\app.log",
"\\nas\backup\app.log"
)
Copy-Item @copyArgs -Force
# Equivalent to:
Copy-Item "C:\Logs\app.log" "\\nas\backup\app.log" -Force
Array splatting is less common than hashtable splatting because positional binding is fragile — if a cmdlet changes parameter order in a future version, your array silently maps to the wrong parameters.
Dynamic Parameter Building
One of the most powerful splatting use cases is building the parameter set conditionally at runtime. You start with a base hashtable and add keys based on logic:
function Copy-FileWithOptions {
param(
[string]$Source,
[string]$Destination,
[switch]$Compress,
[switch]$Recurse
)
$robocopyArgs = @{
Source = $Source
Destination = $Destination
}
if ($Recurse) { $robocopyArgs['Recurse'] = $true }
if ($Compress) { $robocopyArgs['Filter'] = '*.gz' }
# Or pass to Copy-Item
Copy-Item -Path $robocopyArgs.Source -Destination $robocopyArgs.Destination
}
Splatting Across Multiple Commands
Reuse the same hashtable across multiple commands when they share common parameters — a typical pattern for remote commands where the target computer name appears repeatedly:
$session = @{
ComputerName = "Server01"
Credential = $cred
ErrorAction = "Stop"
}
$disk = Get-CimInstance @session -ClassName Win32_LogicalDisk
$os = Get-CimInstance @session -ClassName Win32_OperatingSystem
$service = Get-Service @session -Name "Spooler"
Combining Splat with Inline Parameters
You can mix @splat with explicit inline parameters on the same command line. The inline parameters take precedence if there is a conflict between the hashtable and the explicit value:
$base = @{
SmtpServer = "smtp.corp.com"
From = "[email protected]"
UseSsl = $true
}
# Override Subject and To for each alert type
Send-MailMessage @base -To "[email protected]" -Subject "DB Alert"
Send-MailMessage @base -To "[email protected]" -Subject "Infra Alert"
Splatting and $PSBoundParameters
$PSBoundParameters is a hashtable that PowerShell populates automatically with every parameter explicitly passed to the current function. Combined with splatting, it is the standard way to forward parameters to an inner command without re-listing them:
function Invoke-SafeRobocopy {
[CmdletBinding()]
param(
[string]$Source,
[string]$Destination,
[switch]$WhatIf
)
Write-Verbose "Starting copy from $Source to $Destination"
# $PSBoundParameters already contains Source, Destination, WhatIf as passed
Copy-Item -Path $Source -Destination $Destination -WhatIf:($PSBoundParameters.ContainsKey('WhatIf'))
}
Common Errors and Fixes
-
@ vs $ — wrong sigil prevents splatting.
$paramspasses the hashtable object as a single argument value;@paramssplats it. If you see the hashtable printed as a value in an error, you used$when you needed@. -
Hashtable key must match parameter name exactly. The key
ComputerNamemaps to the-ComputerNameparameter. A key namedComputer_NameorComputernamewill generate an error about an unexpected argument. Check the exact parameter name withGet-Help <cmdlet> -Parameter *.
Related Cmdlets / See Also
Wrapping Up
Splatting is one of the most impactful readability improvements you can make to existing PowerShell scripts. Convert any command with more than four parameters to a splat, use dynamic hashtable building for conditional parameter logic, and forward parameters with $PSBoundParameters to eliminate repetitive inner-function calls.


