PowerShell Splatting: Pass Parameters Cleanly

PowerShell Splatting: Pass Parameters Cleanly

PowerShell Tips Editor 2 min read
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. $params passes the hashtable object as a single argument value; @params splats 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 ComputerName maps to the -ComputerName parameter. A key named Computer_Name or Computername will generate an error about an unexpected argument. Check the exact parameter name with Get-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.

Send-Item -To