How do I pass conditional parameters to cmdlet?

Hello,

I need to alter how do I call cmdlet based on value of [switch] parameter passed to the function, is it possible to do like below for example where I want parameter -ChangePasswordAtLogon to be $true if $mustChangeAtNextLogon switch is present or $false if it does not

Set-ADUser -Identity ($username) -ChangePasswordAtLogon $(if ($mustChangeAtNextLogon.IsPresent) {on $true} else {$false})

Store the parameters in a hash table and build the hash table up using IF blocks. Then splat the hash onto set-aduser.

$parameters = @{
    'Identity' = $username
}

If ($mustChangeAtNextLogon) {
    $parameters['ChangePasswordAtLogon'] = $True
}

Set-ADUser @parameters

Thanks,

Can I mix and match when I supply parameter via hash table and directly like below

Set-AdUser @parameter -EA “stop”

Yes, just so long as you don’t specify the same parameter twice. Also, there needs to be at least one parameter in the splat; that’s why I included identity in the hash table.

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? :slight_smile:

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.