Advanced functions - multiple parameter choices

Hi, until recently I used [switch] type parameters to implement advanced function when there are two possible actions (which excludes one another) depending of user input. For instance if there is a need to enable/disable RDP access to given server, two [switch] type parameters (optional) belonging to different parameter sets will do the job just fine. In example above it would be like:

Set-RDPAccess -ComputerName someserver -Enable or
Set-RDPAccess -ComputerName someserver -Disable

However now I have different and more complicated scenario, setting up values for three parameters (a, b, c) of one application (both in registry and .ini file) on given remote computer. None of them is mandatory and any combination is allowed (even none specified - then existing application parameters remain unchanged). Only name of remote computer where app is installed is mandatory thus I have advanced function:

Set-AppParameter -ComputerName someserver -a value1 -b value 2 -c value 3

I am interested in best approach of handling these types of problems. What I did is the following (inside advanced function):

if($a) {$commandA=“script block commands each in one line”} else {$commandA=“”}
if($b) {$commandB=“script block commands each in one line”} else {$commandB=“”}
if($c) {$commandC=“script block commands each in one line”} else {$commandC=“”}
$command = $commandA + $commandB + $commandC
$sbToExecute = [ScriptBlock]::Create($command)
Invoke-Command -ComputerName $ComputerName -ScriptBlock $sbToExecute

I did not test it yet but logic is what I am interested in. This does not look so elegant but it should work - making one script block from three separate script blocks. Is there any better way of handling these types of problems (multiple optional parameters which do not exclude one another like for instance enable/disable something)?

Probably overthinking this. :slight_smile: Just pass your $a, $b, and $c values to the remote script block, and put the if statements in there:

$sbToExecute = {
    if ($using:a) {
        # Do stuff for A
    }

    if ($using:b) {
        # Do stuff for B
    }

    if ($using:c) {
        # Do stuff for C
    }
}

Invoke-Command -ComputerName $ComputerName -ScriptBlock $sbToExecute

In this case, I used the “using:” syntax, which is a nice convenient way of leveraging local variables in a remote script block, but does require that both the client and server are running PowerShell v3 or later. If you need to support PowerShell v2, then try this instead:

$sbToExecute = {
    param ($a, $b, $c)
    
    if ($a) {
        # Do stuff for A
    }

    if ($b) {
        # Do stuff for B
    }

    if ($c) {
        # Do stuff for C
    }
}

Invoke-Command -ComputerName $ComputerName -ScriptBlock $sbToExecute -ArgumentList $a,$b,$c

Thx Dave, I will give it a try. It looks nicer to say at least. Speaking of using modifier and requirements you mentioned, I have been using this modifier very frequently to execute commands remotely on Windows 7/Windows Server 2008 R2 computers (which comes with PowerShell v2 of course) from my Windows 8.1 machine (PowerShell v4 of course there) and every time everything worked well.

Interesting. Everything I’ve read stated that “using:” variables needed PSv3+ on both sides of the connection, but I don’t think I ever tried it myself. I don’t have a PSv2 system online right this second, but I did do a quick test on my Windows 10 machine:

$var = [pscustomobject]@{ Prop1 = 'Whatever' }

icm -ComputerName localhost -ScriptBlock { $null = $using:var; $MyInvocation.MyCommand.Definition }

<#
param($__using_var)
 $null = $__using_var; $MyInvocation.MyCommand.Definition
#>

This is interesting. It looks like they’re converting the “using:” variables into parameters, which would indeed be compatible with downlevel clients. I’ll fire up some PSv2 and v3 systems to see what I can find.

Yes, under the hood something is going on. All clients in my domain environment are running Windows 7 (PS v2) and I always use this modifier to pass local input parameter values to remote session.

That is extremely cool. I just ran a bunch of tests (including using a PSv3 client), and they all behaved the same way. Using variables get converted to parameters, prepended to any existing param block / ArgumentList parameter (if present), and sent in such a way that they’re compatible with PSv2 on the remote side.

I don’t remember where I read or heard that both the client and server side need to be v3 to support this functionality. The help files are not specific on that point: https://technet.microsoft.com/en-ca/library/jj149005(v=wps.620).aspx . Either way, I’ve been telling this wrong for years.

:slight_smile: I am glad to “help” you. Having not been a fan of PowerShell year or two ago, I realized it was such powerful tool at my disposal. Don Jones Ultimate training and various books helped me very much, together with forums like this. Everything started one day when I had to disable more than a hundred users in my domain. Using GUI would have been suicidal so I decided to start learning PowerShell and slowly but surely I have almost stopped using GUI for managing Active Directory, Exchange Server, registry, file system … PowerShell rules!!! BTW a few days ago I started to learn regular expressions - since PowerShell can utilize them with -match, -replace and Select-String I was stunned what can be done with strings. Simply amazing!!!

Speaking of this example here, is there any way to “force” using of at least one optimal parameter barring making parameter mandatory or only solution is to display warning that none of parameters has been specified in function call?