PowerShell / PowerShellStandard

MIT License
158 stars 23 forks source link

PSCmdlet.MyInvocation.BoundParameters contains values from previous invocations in pipeline #96

Open skaempfer opened 2 years ago

skaempfer commented 2 years ago

My setup:

I have the following C# cmdlet:

[Cmdlet(VerbsDiagnostic.Test,"SampleCmdlet")]
public class TestSampleCmdletCommand : PSCmdlet
{
    [Parameter(
        Mandatory = false,
        ValueFromPipelineByPropertyName = true)]
    public string X { get; set; }

    [Parameter(
        Mandatory = false,
        ValueFromPipelineByPropertyName = true)]
    public string Y { get; set; }

    protected override void ProcessRecord()
    {
        if (this.MyInvocation.BoundParameters.ContainsKey(nameof(X)))
        {
            this.WriteObject("X is bound");
        }

        if (this.MyInvocation.BoundParameters.ContainsKey(nameof(Y)))
        {
            this.WriteObject("Y is bound");
        }
    }
}

I use this command in the following script:

$values = @(
    [PSCustomObject] @{ X = "one" },
    [PSCustomObject] @{ Y = "two" }
)
$values | Test-SampleCmdlet

This produces the following output:

X is bound
X is bound
Y is bound

Expected output:

X is bound
Y is bound

Inspecting the state of the PSCmdlet.MyInvocation.BoundParameters dictionary during the second invocation in the pipeline shows that it still contains the key value pair X: "one" from the first invocation. The actual value of the property X of the cmdlet instance is null as expected.

Re-creating the same functionality with a PowerShell function yields the expected result:

function Test-SampleCmdlet
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true)][string] $X,
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true)][string] $Y
    )

    if($MyInvocation.BoundParameters.ContainsKey("X"))
    {
        Write-Output "X is bound";
    }

    if($MyInvocation.BoundParameters.ContainsKey("Y"))
    {
        Write-Output "Y is bound";
    }
}

$values = @(
    [PSCustomObject] @{ X = "one" },
    [PSCustomObject] @{ Y = "two" }
)

$values | Test-SampleCmdlet
# Produces:
# X is bound
# Y is bound