Pass parameter by reference to a cmdlet written in C#
See original GitHub issueI 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
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
Thank you very much, @mklement0 ! I am closing this issue then.
@mklement0 thanks. This blows my mind actually. What is interesting is that if you change $al = [System.Collections.ArrayList] @() to New-Object System.Collections.ArrayList then it will output nothing. Is this a bug in PowerShell?