Introduction to splatting
Splatting is a way of defining the parameters of a command before calling it. This is an important and often underrated technique that the PowerShell team added to PowerShell 2.
Splatting is often used to solve three potential problems in a script:
- Long lines caused by commands that need many parameters
- Conditional use of parameters
- Repetition of parameters across several commands
Individual parameters are written in a hashtable (@{}
), and then the @
symbol is used to tell PowerShell that the content of the hashtable should be read as parameters.
This example supplies the Name
parameter for the Get-Process
command, and is normally written as Get-Process -Name explorer
:
$getProcess = @{
Name = 'explorer'
}
Get-Process @getProcess
In this example, getProcess
is used as the name of the variable for the hashtable. The name is arbitrary; any variable name can be used.
Splatting can be used with cmdlets, functions, and scripts. Splatting can be used when the call operator is present, for example:
$getProcess = @{
Name = 'explorer'
}
& 'Get-Process' @getProcess
The ability to use splatting with the call operator is useful if the command name itself is held in a variable.
The uses of splatting are explored in the following sections.
Splatting to avoid long lines
The benefit of splatting is most obvious when working with commands that expect a larger number of parameters.
This first example uses the module ScheduledTasks
to create a basic task that runs once a day at midnight:
$taskAction = New-ScheduledTaskAction -Execute pwsh.exe -Argument 'Write-Host "hello world"'
$taskTrigger = New-ScheduledTaskTrigger -Daily -At '00:00:00'
Register-ScheduledTask -TaskName 'TaskName' -Action $taskAction -Trigger $taskTrigger -RunLevel 'Limited' -Description 'This line is too long to read'
Each of the commands is spread out over multiple lines; it is hard to see where one ends and the next begins.
Commands can also be spread out using a backtick, the escape character in PowerShell, as shown here:
$taskAction = New-ScheduledTaskAction `
-Execute pwsh.exe `
-Argument 'Write-Host "hello world"'
$taskTrigger = New-ScheduledTaskTrigger `
-Daily `
-At '00:00:00'
Register-ScheduledTask `
-TaskName 'TaskName' `
-Action $taskAction `
-Trigger $taskTrigger `
-RunLevel 'Limited' `
-Description 'This line is too long to read'
This approach is relatively common, but it is fragile. It is easy to miss a backtick from the end-of-line, or to accidentally add a space after a backtick character. Both break continuation and the command executes but with an incomplete set of parameters; afterward, an error may be displayed, or a prompt may be shown, depending on the parameter (or parameters) it missed.
This problem is shown in the following screenshot, where a space character has been accidentally included after a backtick following the Daily
switch parameter:
Figure 1.6: Space after the escape character
Splatting provides a neater, generally easier-to-read, and more robust alternative. The following example shows one possible way to tackle these commands when using splatting:
$newTaskAction = @{
Execute = 'pwsh.exe'
Argument = 'Write-Host "hello world"'
}
$newTaskTrigger = @{
Daily = $true
At = '00:00:00'
}
$registerTask = @{
TaskName = 'TaskName'
Action = New-ScheduledTaskAction @newTaskAction
Trigger = New-ScheduledTaskTrigger @newTaskTrigger
RunLevel = 'Limited'
Description = 'Splatting is easy to read'
}
Register-ScheduledTask @registerTask
Switch parameters may be treated as if they are Boolean when splatting.
The Daily
parameter that was defined in the previous example is a switch parameter.
The same approach applies to Confirm
, Force
, WhatIf
, Verbose
, and so on.
Conditional use of parameters
Conditional use of parameters is one of the most important ways in which splatting can help.
If a command must be run and the parameters for a command can change based on user input or other circumstances, then it may be tempting to repeat the entire command. For example, a Credential
parameter might be conditionally used.
The command may be repeated entirely based on there being a value for the Credential
variable:
if ($Credential) {
Get-ADUser 'Enabled -eq $true' -Credential $Credential
} else {
Get-ADUser 'Enabled -eq $true'
}
The disadvantage of this approach is that any change to the command must be repeated in the second version.
Alternatively, a splatting variable may be used, and the Credential
parameter added only when it is needed:
$params = @{}
if ($Credential) {
$params['Credential'] = $Credential
}
Get-ADUser 'Enabled -eq $true' @params
Using splatting in this manner ensures only one version of the command must be maintained, reducing the risk of introducing a bug when making changes.
Splatting to avoid repetition
Splatting may be used to avoid repetition when a parameter must be optionally passed on to several different commands. It is possible to splat more than one set of parameters.
In this example, the ComputerName
and Credential
parameters are used by two different commands:
# Parameters used to authenticate remote connections
$remoteParams = @{
Credential = Get-Credential
ComputerName = $env:COMPUTERNAME
}
# Parameters which are specific to Test-WSMan
$testWSMan = @{
Authentication = 'Default'
ErrorAction = 'SilentlyContinue'
}
# By default, do not pass any extra parameters to New-CimSession
$newCimSession = @{}
if (-not (Test-WSMan @testWSMan @remoteParams)) {
# If WSMan fails, use DCOM (RPC over TCP) to connect
$newCimSession['SessionOption'] = New-CimSessionOption -Protocol Dcom
}
# Parameters to pass to Get-CimInstance
$getCimInstance = @{
ClassName = 'Win32_Service'
CimSession = New-CimSession @newCimSession @remoteParams
}
Get-CimInstance @getCimInstance
This example takes advantage of several features:
- It is possible to splat no parameters using an empty hashtable (
@{}
) when all the parameters are conditionally added. - It is possible to test conditions and dynamically add parameters at runtime (if needed).
- It is possible to splat more than one set of parameters into a command.
As the preceding example shows, it is possible to dynamically choose the parameters that are passed to a command without having to write the command in full more than once in a script.
Splatting and positional parameters
It is possible, although rare and inadvisable in production scripts, to splat positional parameters; that is, to splat a parameter without stating a parameter name.
This can be seen with the Rename-Item
command, which has two positional parameters: Path
and NewName
. Rename-Item
may be run as follows:
Rename-Item oldname.txt newname.txt
An array to splat these positional parameters looks as follows:
$renameItem = 'oldname.txt', 'newname.txt'
Rename-Item @renameItem
A splatting variable with positional parameters may be used with executable files (.exe
files), although it is often difficult to see any difference between splatting and using a normal variable. For example, both of the following commands execute in the same way:
$argumentList = '/t', 2
timeout.exe $argumentList
timeout.exe @argumentList
Splatting is a powerful technique and can be used to make code more readable by reducing the line length or repetition.
When using splatting, string values in the hashtable must be quoted. Conversely, when using a parameter directly, it is often unnecessary. The parser is responsible for deciding how statements and expressions should be interpreted.