What is PowerShell splatting and how does it work?

feature-image.png

Introduction

PowerShell splatting is an interesting phrase that refers to a technique used to pass parameter values to a PowerShell command. Instead of supplying a long list of parameters, splatting allows you to use PowerShell objects containing parameter values instead. This helps make your code easier to read and allows you to reuse parameter values between commands more efficiently.

In this tutorial, you’ll learn everything there is to know about PowerShell splatting to help you write more awesome code!

Prerequisites

To follow along with this tutorial, you’ll need to have PowerShell 7.1 installed. Splatting has been around since PowerShell 2.0, but some of the techniques described in this article, such as overriding splatted parameters, have only been available since version 7.1.

What is PowerShell splatting?

First, you’ll need to be familiar with the basic named and positional PowerShell parameter types. For named parameters, you provide both a parameter name and value to a command; for example:

# Copy a text file using the Path and Destination named parameters.
Copy-Item -Path ".\source.txt" -Destination ".\dest.txt"

For positional parameters, you simply provide the parameter values in the correct order, as you’ll see below. The required order is determined by the command itself.

# This works because Copy-Item accepts Path as the first parameter and Destination as the second.
# Other commands will be configured differently.
Copy-Item ".\source.txt" ".\dest.txt"

These two methods are fine, but can quickly become difficult to deal with once you have many parameters for a command. This is where splatting comes in.

Splatting named parameters using hashtables

To use splatting with named parameters, you first create a hashtable containing key/value pairs for each parameter/value. Then, you pass this variable to the command, replacing the dollar symbol ($) in the name with an At symbol (@); for example:

# Create a hashtable containing the parameters and values.
$Params = @{
    Path = ".\source.txt"
    Destination = ".\dest.txt"
}

# Splat the parameters to the Copy-Item command using the hashtable name with the @ symbol.
Copy-Item @Params

Splatting positional parameters using arrays

To use splatting with positional parameters, you create an array containing each parameter value in the correct order and pass this to the command, in the same way as above; for example:

# Create an array containing each parameter value in the correct ordered position.
$Params = @(
    ".\source.txt",
    ".\dest.txt"
)

# Splat the parameter values to the Copy-Item command using the array name with the @ symbol.
Copy-Item @Params

Combining explicit and splatted parameters

It’s often useful to combine parameter splatting with explicitly defined parameters. For example, you might want to include the WhatIf switch parameter to test a copy operation before actually copying the files, as you’ll see below.

# Create a hashtable containing the parameters and values.
$Params = @{
    Path = ".\source.txt"
    Destination = ".\dest.txt"
}

# Splat the $Params hashtable to the Copy-Item command and also specify the WhatIf parameter explicitly.
Copy-Item @Params -WhatIf

If you wanted to splat the WhatIf parameter, you’d need to set the value to $true in the splatting hashtable or array.

Overriding splatted parameters

In the previous example, you combined splatted and explicitly defined parameters. With the release of PowerShell 7.1, you can now override a splatted parameter in a similar way; for example:

# Create a hashtable containing the parameters and values.
$Params = @{
    Path = ".\source.txt"
    Destination = ".\dest.txt"
    WhatIf = $true
}

# Splat the $Params hashtable to the Copy-Item command and override the WhatIf parameter.
Copy-Item @Params -WhatIf:$false

In previous versions of PowerShell this will throw an error complaining that the WhatIf parameter is specified more than once.

Reusing splatted parameters

Another useful application of splatting is to define a set of parameters once, and then reuse them in subsequent commands; for example:

# Create a hashtable containing the parameters and values to reuse.
$Params = @{
    Path = ".\source\"
    Force = $true
    Include = "*.txt"
}

# Copy all txt files in the .\source\ directory to .\destination-one\
Copy-Item @Params -Destination ".\destination-one\"

# Reuse the splatting hashtable to copy all txt files in the .\source\ directory to .\destination-two\.
# It doesn't matter which position you put the splatting hashtable.
Copy-Item -Destination ".\destination-two\" @Params

Forwarding parameters using $PSBoundParameters

The $PSBoundParameters variable is an automatic variable, which contains a dictionary of the parameters (and values) passed to a script or function. In the example below, you’ll see how you can use splatting to forward the parameters from one function (Invoke-FuncTwo) to another (Invoke-FuncOne) using the $PSBoundParameters variable. This is an advanced technique and can take some getting your head around, but it does open up some interesting possibilities once you understand it.

function Invoke-FuncOne {
    param ($a, $b, $c)
    $Output = ""
        if ($a) {$Output += $a}
        if ($b) {$Output += $b}
        if ($c) {$Output += $c}
        Write-Output $Output
}

function Invoke-FuncTwo {
    param ($a, $b, $c)

    # Call the Invoke-FuncOne function and pass the $a, $b, and $c parameters
    # by splatting the @PSBoundParameters variable.
    Invoke-FuncOne @PSBoundParameters

    # Call the Invoke-FuncOne function again, this time with the $a and $c
    # parameters, but not with $b.
    $LimitedParameters = $PSBoundParameters
    $LimitedParameters.Remove("b") | Out-Null
    Invoke-FuncOne @LimitedParameters
}
Output
PS C:\> Invoke-FuncTwo -a "Hello" -b "World" -c "!"
HelloWorld!
Hello!
Output showing Invoke-FuncTwo splatting its parameters to Invoke-FuncOne.

Using splatting with proxy functions

Proxy functions are another advanced PowerShell technique. They’re essentially a wrapper for an existing command, allowing you to add functionality not already implemented. Using the $Args automatic variable, which contains all unassigned parameters (i.e., parameters that are not named in the param block), you can pass parameters to a proxy function and then use splatting to pass them onto the existing command; for example:

# Define a function to simply pass all parameters to the Get-Process command by
# splatting the @Args variable.
function Get-ProcessProxy {
    Get-Process @Args
}

# Call the proxy function and specify a parameter called Name.
Get-ProcessProxy -Name "powershell"
Output
PS C:\> Get-ProcessProxy -Name "powershell"

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     25    56.82      50.62       0.00   14832   0 powershell
     26    56.70      24.09       0.00   21068   0 powershell
Example showing proxy function output.

You can also use the $Args variable combined with named parameters (i.e., those in the param block of a function):

# Define a function with named parameters $a and $b that also passes any other parameters
# to Get-Process by splatting the @Args variable.
function Get-ProcessProxy {
    param (
        [bool] $a,
        [string] $b
    )
    if ($a) {Get-Process @Args}
    if ($b) {Write-Output $b}
}

# When $a is true, Get-Process will be called and the Name parameter will be passed.
Get-ProcessProxy -Name "powershell" -a:$true

# When $b is specified, its value will be printed to the console using Write-Output.
Get-ProcessProxy -Name "powershell" -b "Nope, not today!"
Output
PS C:\> Get-ProcessProxy -Name "powershell" -a:$true

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     25    56.82      44.68       0.00   14832   0 powershell
     26    56.76      23.83       0.00   21068   0 powershell
     25    56.85      27.45       0.00   22684   0 powershell
     26    57.57      22.76       0.00   23800   0 powershell
     25    56.91      23.14       0.00   31348   0 powershell
     25    57.19      23.48       0.00   37496   0 powershell
     25    57.61      27.57       0.00   39124   0 powershell
     25    57.56      25.48       0.00   41688   0 powershell
     25    57.09      23.49       0.00   47316   0 powershell

PS C:\> Get-ProcessProxy -Name "powershell" -b "Nope, not today!"
Nope, not today!
Another example showing proxy function output.

The $Args variable will not contain any of the named parameters.

Why not just use backticks?

There is one other technique that you might come across: namely, the use of backticks ` to break the command line, so that code becomes more readable; for example:

Copy-Item -Path ".\source\" `
    -Destination ".\dest\" `
    -Include "*.txt" `
    -Force

This is widely seen as a bad choice. Backticks are hard to read, easy to miss, and easy to mistype. Also, if you accidentally enter a space after a backtick, the command will fail with an error, as you’ll see below.

Output
PS C:\> Copy-Item -Path ".\source\" `
>>     -Destination ".\dest\" `
>>     -Include "*.txt" `
>>     -Force
#error
Copy-Item: Cannot find path 'C:\source\' because it does not exist.
-Destination:
Line |
   2 |      -Destination ".\dest\" `
     |      ~~~~~~~~~~~~
     | The term '-Destination' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
#enderror
Output showing an error due to a single white space entered after the backtick on the first line.

This causes unnecessary confusion and can be hard to debug given that the error message is not usually very helpful. The bottom line is that splatting is a much better option.

Conclusion

In this tutorial, you’ve worked through examples of all the different splatting techniques. Learning how to combine these techniques gives you plenty of options to simplify complex code and make it easier to read. So, make sure your next scripts use splatting and keep writing awesome code!

×