Just to elaborate onto what Craig Duff said, you can take splatting to a ‘next level’ by creating your functions with exactly the same parameter names and types as the cmdlets you call within your functions.
This means that you no longer need to perform parameter verification yourself, as you’re passing the job of doing that to the cmdlet.
Here’s a quick example:
function Get-CimNamespace
{
[CmdletBinding(DefaultParameterSetName = 'ComputerNameSet')]
param
(
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSessionSet', Position = 0)]
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerNameSet', Position = 0)]
[ValidateNotNullOrEmpty()]
[string]$Namespace,
[Parameter(ValueFromPipeline = $true, ParameterSetName = 'ComputerNameSet')]
[string[]]$ComputerName,
[Parameter(ValueFromPipeline = $true, ParameterSetName = 'CimSessionSet')]
[Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSessionSet')]
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerNameSet')]
[ValidateNotNullOrEmpty()]
[string]$Filter,
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSessionSet')]
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerNameSet')]
[UInt32]$OperationTimeoutSec,
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSessionSet')]
[Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerNameSet')]
[string[]]$Property
)
Process
{
try
{
Get-CimInstance -ClassName __Namespace @PSBoundParameters -ErrorAction Stop
}
catch
{
$errorRecord = New-ErrorRecord -Exception $_.Exception -ErrorCategory $_.CategoryInfo.Category -ErrorId $_.FullyQualifiedErrorId -TargetObject $_.CategoryInfo.TargetName
$PSCmdlet.WriteError($errorRecord)
}
}
}
This is a very simple function that retrieves a list of WMI classes in a given namespace. The only thing my function cares about directly is the namespace you provide (actually not even that since it defaults to root\cimv2…). However, Get-CimInstance accepts a lot of other parameters, such as ComputerName, CimSession, Filter, etc etc (it also accepts more than the ones I’ve added there, but adding the ones I’ve left out would have broken my function, which is why I chose not to add them). For completeness, I allow all of those parameters to be received by my function, but notice I do absolutely no validation on the parameters at all. I just pass it all to Get-CimInstance and let it handle it.
Any validation tests I come up with myself are probably going to be lacking in comparison to what Get-CimInstance already does, so why not ask Get-CimInstance to do the validation for me?
Then you can see I have a try…catch (yes, no throws here :P) and I take the error I receive, modify a few things in it (New-ErrorRecord is my own helper function) and re-throw the error again.
This is just to ensure that instead of the user seeing an error coming from Get-CimInstance (which they didn’t invoke because they called Get-CimNamespace) on some line their script does not have… they now see the error as coming from the line that invoked Get-CimNamespace with the error being on Get-CimNamespace.
The variable $PSBoundParameters contains all parameters that were passed to the function, and I’m just splatting those to Get-CimInstance.
If my $PSBoundParameters had too many parameters, let’s say if my Get-CimNamespace function accepted a parameter called ‘HelloWorld’ (which is not accepted by Get-CimInstance) I would need to remove it from $PSBoundParameters before splatting it to Get-CimInstance.
That can be done as such:
$PSBoundParameters.Remove('HelloWorld')
Notice that doing so does NOT delete the value of $HelloWorld, I can still access $HelloWorld directly inside my function and access it’s value, but it will be removed from the $PSBoundParameters variable.