Skip to content

Pass parameter by reference to a cmdlet written in C#  #14384

@AlexKichkailo

Description

@AlexKichkailo

I am trying to write a simple PowerShell cmdlet in C# that accepts an instance of ArrayList and adds an item to it. The issue I've encountered is that cmdlet receives a copy of the collection so modifying it inside the cmdlet does not work. I assume that this is an intended behavior, but cannot find any proof for that in the documentation. I looked specifically here: https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/cmdlet-overview?view=powershell-7.1, but also read other sections. Below is a program to reproduce the issue. Can anyone point to the documentation or explain why cmdlet parameter binding works this way please?

Steps to reproduce

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace CustomPowerShellCmdlet
{
    class Program
    {
        static void Main(string[] args)
        {
            string powerShellScript = @"
Write-Output ('PowerShell Version is ' + $PSVersionTable.PSVersion)

$A  = New-Object System.Collections.ArrayList
$A.Add('3') | Out-Null
Write-Output  ('Count is ' + $A.Count)

$B  = New-Object System.Collections.ArrayList
Add-CollectionItem -Collection $B -Item '1'
Add-CollectionItem -Collection $B -Item '2'
foreach ($Item in $B) {
    Write-Output $Item
}
Write-Output  ('Count is ' + $B.Count)
";

            var output = RunPowerShellScript(powerShellScript);

            foreach (PSObject psObject in output)
            {
                Console.WriteLine(psObject.BaseObject.ToString());
            }
        }

        private static Collection<PSObject> RunPowerShellScript(string powerShellScript)
        {
            InitialSessionState initialSessionState = InitialSessionState.CreateDefault();
            initialSessionState.Commands.Add(new SessionStateCmdletEntry("Add-CollectionItem", typeof(AddCollectionItemCmdlet), null));

            using (var runspace = RunspaceFactory.CreateRunspace(initialSessionState))
            {
                runspace.Open();

                using (var ps = PowerShell.Create())
                {
                    ps.Runspace = runspace;

                    ps.AddScript(powerShellScript);


                    return ps.Invoke();
                }
            }
        }

        [Cmdlet(VerbsCommon.Add, "CollectionItem")]
        public class AddCollectionItemCmdlet : Cmdlet
        {
            [Parameter(Mandatory = true)]
            [AllowEmptyCollection]
            public ArrayList Collection { get; set; }

            [Parameter(Mandatory = true)]
            public object Item { get; set; }

            protected override void BeginProcessing()
            {
                Collection.Add(Item);
            }
        }
    }
}

Expected behavior

Actual behavior


Environment data

PSVersion 7.1.0
PSEdition Core
GitCommitId 7.1.0
OS Microsoft Windows 10.0.19041
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0


Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions