How to use splatting in PowerShell

I still hear a lot of people who dont know how splatting works in Powershell. Splatting was introduced in Powershell 2.0 so it has been around for a while and it can make scripts look more clean and easy to read. This is how Microsoft explains splatting:
Splatting is a method of passing a collection of parameter values to a command as unit. Windows PowerShell associates each value in the collection with a command parameter
I will give some examples on how to use splatting and show why it can be useful. Splatting can be used either with arrays or hashtables. Arrays are used for commands that have positional parameters and hash tables are used when named parameters are needed.

Array splatting

Lets start with an example and splat parameters into an array. First you need a command that accepts positional parameters (parameters you can use without naming them). I will use Invoke-Command in this example, which has two positional parameters (ComputerName and ScriptBlock) and can be used in the folling way:
Invoke-Command Server01 'C:\script.ps1'
If we want to use splatting on this we would add these two parameter values to an array first and then add the array to the command instead of the parameters.
$params = 'Server01', 'C:\script.ps1'
Invoke-Command @params
If you look closely you can see that the variable $params starts with a dollar symbol, but when its used in splatting the "@" symbol is used. The "@" symbol tells PowerShell that this variable is a collection of parameters and should be treated as parameters. If a dollar symbol was used PowerShell would just consider it to be an array of values to the first positional parameter and thats not what we want in this case.

You can also mix this technique with regular parameters if needed:
$params = 'Server01', 'C:\script.ps1'
Invoke-Command @params -ErrorVariable Err

Hash table splatting

Not all parameters are positional and using positional parameters can make the code harder to read. I prefer to use named parameters as often as possible, even if it means more letters to punch in.
If we want to use splatting with named parameters we need to use a hash table instead of an array.

I will go straight to examples which probably explains this better than words. I will use my own cmdlet, Write-ObjectToSQL, which I wrote about some time back. This cmdlet has quite a few parameters which makes it a good candidate, since the command line can get quite long as you can see in the example below.

The command below will get all the processes running on the machine and write all the information to a database table. Exactly what it does is not important for this topic. You can read more details about this cmdlet here.
Get-Process | Write-ObjectToSQL -Server localhost\sqlexpress -Database MyDB -TableName MyTable -ReportEveryXObject 100
Now lets use splatting with a hash table where every key/value pair represents a named parameter.
$params = @{
    'Server'             = 'localhost\sqlexpress'
    'Database'           = 'MyDB'
    'TableName'          = 'MyTable'
    'ReportEveryXObject' = 100
}
Get-Process | Write-ObjectToSQL @params
Again, the "@" symbol on the last line is the magic here, just like when using an array. This works with all kinds of parameters, including switch parameters and common parameters:
$params = @{
    'Server'             = 'localhost\sqlexpress'
    'Database'           = 'MyDB'
    'TableName'          = 'MyTable'
    'ReportEveryXObject' = 100
    'DoNotCreateTable'   = $true
    'ErrorVariable'      = 'err'
}
Get-Process | Write-ObjectToSQL @params
You can mix with regular parameters as well.
$params = @{
    'Server'             = 'localhost\sqlexpress'
    'Database'           = 'MyDB'
    'TableName'          = 'MyTable'
    'ReportEveryXObject' = 100
    'DoNotCreateTable'   = $true
    'ErrorVariable'      = 'err'
}
Get-Process | Write-ObjectToSQL @params -Verbose
However, you cannot add the same parameter more than once.
$params = @{
    'Server'             = 'localhost\sqlexpress'
    'Database'           = 'MyDB'
    'TableName'          = 'MyTable'
}
Get-Process | Write-ObjectToSQL @params -TableName MyOtherTable
#Error: Cannot bind parameter because parameter TableName is specified more than once
To read more about this topic write "Get-Help about_splatting" in the PowerShell console or read the web version here.

No comments

Post a Comment