0

Building on this technique to use Cmdlets as "delegates" I am left with this question:

Is there a way to pass a commandlet with prescribed named or positional parameters to another commandlet that uses the powershell pipeline to bind the remaining parameters to the passed commandlet?

Here is the code snippet I'd like to be able to run:

Function Get-Pow{
    [CmdletBinding()] 
    Param([Parameter(ValueFromPipeline=$true)]$base,$exp)
    PROCESS{[math]::Pow($base,$exp)}
}
Function Get-Result{
    [CmdletBinding()]
    Param([Parameter(ValueFromPipeline=$true)]$x,$Cmdlet)
    $x | . $Cmdlet
}

10 | Get-Result -Cmdlet 'Get-Pow -exp 2'
10 | Get-Result -Cmdlet 'Get-Pow -exp 3'
10 | Get-Result -Cmdlet Get-Pow -exp 2
10 | Get-Result -Cmdlet Get-Pow -exp 3

The first two calls to Get-Result result in CommandNotFoundException because Get-Pow -exp 2 "is not the name of a cmdlet."

The last two calls to Get-Result result in NamedParameterNotFound,Get-Result since that syntax is actually attempting to pass parameter -exp to Get-Result which it does not have.

Is there some other way to set this up so it works?

alx9r
  • 3,675
  • 4
  • 26
  • 55
  • 1
    You could have an optional parameter for Get-Results that could accept these arguments? In the form of a hashtable maybe? – Matt Feb 12 '15 at 19:52
  • @Matt I didn't find a way to pass parameters on the `$x | . $Cmdlet` line. But I did manage to get your "optional parameter" method working with `Invoke-Expression`. See my answer below. – alx9r Feb 12 '15 at 20:54
  • I take it back, `$x | . $Cmdlet @arguments` can also be made to work. – alx9r Feb 12 '15 at 21:07

1 Answers1

1

I'm not sure this is the best method, but at least it resembles powershell idioms throughout:

Function Get-Amount{
    [CmdletBinding()] 
    Param(
    [Parameter(ValueFromPipeline=$true)]$t,
    [Parameter(position=1)]$r,
    [Parameter(position=2)]$P)
PROCESS{$P*[math]::Pow(1+$r,$t)}
}
Function Get-Result{
    [CmdletBinding()]
    Param(
    [Parameter(ValueFromPipeline=$true)]$x,
    [Parameter(Position=1)]$Cmdlet,        #positional arguments here makes calling more readable
    [Alias('args')]                        #careful, $args is a special variable
    [Parameter(Position=2)]$Arguments=@()) #the default empty array is required for delegate style 1
PROCESS{
    #invoke style 1                        #works with delegate styles 1,2,3
    iex "$x | $Cmdlet @Arguments"          

    #invoke style 2                        #works with delegate styles 2,3
    $x | . $Cmdlet @Arguments              
}}

5,20 | Get-Result 'Get-Amount -r 0.05 -P 100' #delegate style 1
5,20 | Get-Result Get-Amount 0.05,100         #delegate style 2
5,20 | Get-Result Get-Amount @{r=0.05;P=100}  #delegate style 3

Which results in:

127.62815625
CommandNotFoundException
265.329770514442
CommandNotFoundException
127.62815625
127.62815625
265.329770514442
265.329770514442
127.62815625
127.62815625
265.329770514442
265.329770514442
alx9r
  • 3,675
  • 4
  • 26
  • 55