开发者

Powershell: inspect, consume and pass through arguments?

开发者 https://www.devze.com 2022-12-07 22:05 出处:网络
I have a script (let\'s call it caller.ps1) that invokes another script callee.ps1. In caller.ps1, I want to inspect some arguments and pass them on, along with some other arguments to callee.ps1

I have a script (let's call it caller.ps1) that invokes another script callee.ps1. In caller.ps1, I want to inspect some arguments and pass them on, along with some other arguments to callee.ps1

caller:

param (
[Parameter(Mandatory, ParameterSetName="ByA")][string]$a, // passthru
[Parameter(Mandatory, ParameterSetName="ByB")][string]$b, // passthru
// some more passthru parameters
[Parameter()][switch]$inspect,  // inspect, then pass on
[Parameter()][switch]$consume   // consume, do not pass on
)
callee:

param (
[Parameter(Mandatory, ParameterSetName="ByA")][string]$a,
[Parameter(Mandatory, ParameterSetName="ByB")][string]$b,
// some more parameters
[Parameter()][switch]$i开发者_开发技巧nspect
)

what's the best practice here? I have tried @args but it looks like it's empty. I suppose that's because all the arguments are bound to names?

Since I have two ParameterSets "ByA" and "ByB", and a bunch of switch parameters, it'd be super clunky to inspect each one and compose a new argument list for callee. Is there an elegant way of doing this? Thanks.


The automatic variable $PSBoundParameters is very useful in this case, it will allow you to pass through the same arguments to the next scriptblock as long as the parameters name from the callee either have the same name or have aliases that match the ones from the caller.

Using 2 scriptblocks to demonstrate but the logic is exactly the same as with 2 .ps1 files.

$caller = {
    param (
        [Parameter(Mandatory, ParameterSetName="ByA")]
        [string] $a,

        [Parameter(Mandatory, ParameterSetName="ByB")]
        [string] $b,

        [Parameter()]
        [switch] $inspect,

        [Parameter()]
        [switch] $consume
    )

    # remove the bound parameter before calling the next script
    $null = $PSBoundParameters.Remove('consume')
    # do whatever you need here with `$consume` then
    # call the next script using the bounded parameters
    & $callee @PSBoundParameters
}

$callee = {
    param (
        [Parameter(Mandatory, ParameterSetName="ByA")]
        [string] $a,

        [Parameter(Mandatory, ParameterSetName="ByB")]
        [string] $b,

        [Parameter()]
        [switch] $inspect
    )

    $PSBoundParameters
}

& $caller -a 'hey there' -inspect -consume

As for why $args didn't work, as the documentation states, $args only works on undeclared parameters and your scripts are using a param block (declared parameters) and will not allow undeclared ones because these are advanced scriptblocks / functions in a sense due to the Parameter attribute declarations.

A simple example to visualize what this means:

In this example, the scriptblock only has 2 declared parameters and 3 arguments being passed, 1 and 2 are bound to the declared parameters and 3 is passed as an undeclared parameter hence is bound to $args:

# works fine, outputs 3
& {param($paramA, $paramB) $args } -paramA 1 -paramB 2 3

Now if we try to do the same with an advanced scriptblock we will see an error because these don't allow undeclared parameters:

# Fails: A positional parameter cannot be found that accepts argument '3'.
& {[CmdletBinding()]param($paramA, $paramB) $args } -paramA 1 -paramB 2 3
0

精彩评论

暂无评论...
验证码 换一张
取 消