3

I can't seem to be able to pass in a reference parameter to PowerShell from C#. I keep getting the following error:

"System.Management.Automation.ParentContainsErrorRecordException: Cannot process argument transformation on parameter 'Test'. Reference type is expected in argument."

Example:

For the simple script:

Param (
[ref]
$Test
)

$Test.Value = "Hello"
Write-Output $Test

And here's the C# code:

string script = {script code from above};
PowerShell ps = PowerShell.Create();
ps = ps.AddScript($"New-Variable -Name \"Test\" -Value \"Foo\""); // creates variable first
ps = ps.AddScript(script)
        .AddParameter("Test", "([ref]$Test)"); // trying to pass reference variable to script code

ps.Invoke(); // when invoked, generates error "Reference type is expected in argument

I've tried AddParameter as well as AddArgument.

What I have gotten to work is to create my script first as a script block:

ps.AddScript("$sb = { ... script code ...}"); // creates script block in PowerShell
ps.AddScript("& $sb -Test ([ref]$Test)"); // executes script block and passes reference parameter
ps.AddScript("$Test"); // creates output that shows reference variable has been changed

Any help?

4
  • 1
    What help are you looking for? You already said/shown you can get your result using your script block workaround. Why stress out for something different? Why do you believe using a script blick is a bad thing? Commented Mar 12, 2020 at 4:12
  • 1
    Fair point - I should have said that I wanted to understand why my first approach wasn't working, in an effort to better understand the C# interface to PowerShell as the documentation is very limited. Commented Mar 12, 2020 at 11:37
  • 1
    To note, though, the solution from @mklement0 is better than my script block approach because I don't have to explicitly output the [ref] variable in PS in order to know the output variable. Instead, I can just check the C# PSReference object I pass to AddParameter. Commented Mar 12, 2020 at 12:08
  • Understood. So, please update your post to show what you did as well for the clarity of others that may dine the need for the same approach. Commented Mar 12, 2020 at 15:41

1 Answer 1

3

I can't seem to be able to pass in a reference parameter to PowerShell from C#

The only way to make your original approach work is to create your [ref] instance in C# and pass that, which means creating an instance of System.Management.Automation.PSReference and passing that to your .AddParameter() call:

// Create a [ref] instance in C# (System.Management.Automation.PSReference)
var psRef = new PSReference(null);

// Add the script and pass the C# variable containing the
// [ref] instance to the script's -Test parameter.
ps.AddScript(script).AddParameter("Test", psRef);

ps.Invoke();

// Verify that the C# [ref] variable was updated.
Console.WriteLine($"Updated psRef: [{psRef.Value}]");

The above yields Updated psRefVar: [Hello]


Full code:

using System;
using System.Management.Automation;

namespace demo
{
  class Program
  {
    static void Main(string[] args)
    {
      var script = @"
        Param (
        [ref]
        $Test
        )

        $Test.Value = 'Hello'
        Write-Output $Test
        ";

      using (PowerShell ps = PowerShell.Create())
      {
        var psRef = new PSReference(null);
        ps.AddScript(script).AddParameter("Test", psRef);
        ps.Invoke();
        Console.WriteLine($"Updated psRef: [{psRef.Value}]");
      }

    }
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Awesome - thanks! Makes sense. Can you explain the real difference between AddParameter vs. AddArgument? Is it just that AddParameter is named whereas AddArgument relies on PS script referring to $args[] array? Thanks again.
Glad to hear it was helpful, @MikeOliver; an argument is an unnamed value (a mere value, not preceded by a parameter name), passed positionally. For robustness, you should use .AddParameter(). Does that explain it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.