PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Thursday, May 19, 2022

[FIXED] How can I determine the parameters that were bound in just the current pipeline step?

 May 19, 2022     parameterbinding, pipeline, powershell     No comments   

Issue

Consider the following script:

function g
{
    [CmdletBinding()]
    param
    (
        [parameter(ValueFromPipelineByPropertyName = $true)]$x,
        [parameter(ValueFromPipelineByPropertyName = $true)]$y,
        [parameter(ValueFromPipelineByPropertyName = $true)]$z
    )
    process
    {
        $retval = @{psbp=@{};mibp=@{};x=$x;y=$y;z=$z}
        $PSBoundParameters.Keys |
            % { $retval.psbp.$_ = $PSBoundParameters.$_ }
        $PSCmdlet.MyInvocation.BoundParameters.Keys |
            % { $retval.mibp.$_ = $PSCmdlet.MyInvocation.BoundParameters.$_} 
        return New-Object psobject -Property $retval
    }
}

$list = (New-Object psobject -Property @{x=1;z=3}),
        (New-Object psobject -Property @{x=$null;y=2} ) 
$list | 
    g |
    Select bp,x,y,z |
    ft -AutoSize

Running the script results in the following output:

psbp      mibp      x y z
----      ----      - - -
{z, x}    {z, x}    1   3
{y, z, x} {y, z, x}   2 

This seems to reveal that both $PSBoundParameters and $PSCmdlet.MyInvocation.BoundParameters contain the cumulation of all the parameters bound so far.

I'm fairly sure that $x and $z were bound on the first step, and $x and $y were bound on the second step, but I haven't found a way to retrieve that detail programmatically.

How can I determine the parameters that were bound in just the current pipeline step?


Why do I care about this? Some kinds of parameter validation are more complex than can be achieved using language features like parameter sets, ValidateScript(), etc. That validation has to be performed inside the function body. Occasionally it is desirable to consider an unbound parameter to be semantically different from passing $null to that same parameter. Detection of bound parameters is customarily achieved by interrogating $PSBoundParameters. This works fine if you pass only a single parameter object on the pipeline. However, if you pipe a list of parameter objects using the pipeline, that detection is foiled because of the problem demonstrated by the script above. This is violates the principle-of-least surprise because a function that worked fine inside a foreach loop behaves dramatically differently when the caller happens to invoke it by piping those same objects to it.

I can work around this by calling the affected functions from within a foreach, but I'd rather solve the problem for all invocations rather than abandon the pipeline altogether.


Solution

You can remember all parameters bounded by command line in begin block, then in the end of process block you can clean up $PSBoundParameters from parameters bounded by current input object:

function g
{
    [CmdletBinding()]
    param
    (
        [parameter(ValueFromPipelineByPropertyName = $true)]$x,
        [parameter(ValueFromPipelineByPropertyName = $true)]$y,
        [parameter(ValueFromPipelineByPropertyName = $true)]$z
    )
    begin
    {
        $CommandLineBoundParameters=@($PSBoundParameters.Keys)
    }
    process
    {
        ...

        @($PSBoundParameters.Keys) |
            ? { $CommandLineBoundParameters -notcontains $_ } |
            % { [void]$PSBoundParameters.Remove($_) }
    }
}


Answered By - user4003407
Answer Checked By - Marilyn (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing