Home > Enterprise >  Passing parameters from c# to powershell script
Passing parameters from c# to powershell script

Time:10-28

I created a powershell script that consists of:

param($ServerName, $Location)

"Application Name: $ServerName"
"Location: $Location"

when I am in the powershell and I run .\Params.ps1 ConsoleApp1 Washington, D.C. it will display:

Application Name: ConsoleApp1
Location: Washington D.C.

So I know this works just fine. Now I am wanting to take this to c# and perform parameter passing.

In my console application, I created the following:

    static void Main(string[] args)
    {
        string[] scriptParam = { "ConsoleApp1", "Washington, D.C."};
        string powerShell = PerformScript(scriptParam);
        Console.WriteLine(powerShell);
        Console.WriteLine("\nPowershell script excuted!!");          
        Console.ReadLine();
    }

    static string PerformScript(string scriptParameters)
    {
        InitialSessionState runspaceConfiguration = InitialSessionState.Create();
        Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);

        runspace.Open();

        Pipeline pipeline = runspace.CreatePipeline();
       

        PowerShell ps = PowerShell.Create();
        ps.Runspace = runspace;
        ps.AddCommand(@"C:\Users\users\source\repos\ConsoleApp1\powershell\Params.ps1");

        foreach (string scriptParameter in scriptParameters)
        {
            ps.AddParameter(scriptParameter);
        }

        Collection<PSObject> psObjects = pipeline.Invoke();
        runspace.Close();

        StringBuilder stringBuilder = new();

        foreach (PSObject item in psObjects)
        {
            stringBuilder.AppendLine(item.ToString());
        }

        return stringBuilder.ToString();
    }

but when I run the program I get an Exception Unhandled on the line

Collection<PSObject> psObjects = pipeline.Invoke();

System.Management.Automation.PSInvalidOperationException: 'The pipeline does not contain a command.'

Am I doing something incorrect when passing the parameters?


Updated code:

    static string PerformScript(string[] scriptParameters)
    {
        InitialSessionState runspaceConfiguration = InitialSessionState.Create();
        Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);

        runspace.Open();

        Pipeline pipeline = runspace.CreatePipeline();

        using (var ps = PowerShell.Create())
        {
            var result = ps.AddCommand(@"C:\Users\users\source\repos\ConsoleApp1\powershell\Params.ps1")
              .AddArgument("ConsoleApp1")
              .AddArgument("Washington, D.C.")
              .Invoke();
            foreach (var o in result)
            {
                Console.WriteLine(o);
            }
        }

        Collection<PSObject> psObjects = pipeline.Invoke();
        runspace.Close();

        StringBuilder stringBuilder = new();

        foreach (PSObject item in psObjects)
        {
            stringBuilder.AppendLine(item.ToString());
        }

        return stringBuilder.ToString();
    }

CodePudding user response:

Use .AddArgument(), not .AddParameter().

What you're trying to pass are positional (unnamed) arguments, i.e. mere parameter values whose target parameter is implied by their position, which is what .AddArgument() is for.

By contrast, .AddParameter() is for named arguments, where you specify the parameter name first, followed by its value (argument).

Here's a simplified example:

using (var ps = PowerShell.Create()) {
  var result = ps.AddCommand(@"C:\Users\users\source\repos\ConsoleApp1\powershell\Params.ps1")
    .AddArgument("ConsoleApp1")
    .AddArgument("Washington, D.C.")
    .Invoke();
  foreach (var o in result) {
    Console.WriteLine(o);
  }
}

Note: The above uses the much simplified API that is available directly via the methods of a PowerShell instance (created with .Create()): If automatically creating a runspace with a default session state is sufficient, there is no need for explicit creation of a runspace with RunspaceFactory.CreateRunspace(), a session state with InitialSessionState.Create(), and a runspace's pipeline with .CreatePipeline() - see the bottom section for how to apply the techniques to your code.


As for what you tried:

If you mistakenly use .AddParameter() with a single method argument only, what the PowerShell SDK does is to default the omitted parameter value to true, so that .AddParameter('foo') is the equivalent of passing -foo: $true from inside PowerShell.

This works as intended only if you're passing the name of a parameter that is a switch parameter (of type System.Management.Automation.SwitchParameter, [switch] in PowerShell code).


Applied to your code:

static void Main(string[] args)
{
    Console.WriteLine(
      PerformScript(
        @"C:\Users\users\source\repos\ConsoleApp1\powershell\Params.ps1", 
        new string[] { "ConsoleApp1", "Washington, D.C." }
      )
    );
}

static string PerformScript(string scriptPath, string[] scriptArguments)
{
  StringBuilder stringBuilder = new();
  using (var ps = PowerShell.Create())
  {
    ps.AddCommand(scriptPath);
    foreach (var arg in scriptArguments)
    {
      ps.AddArgument(arg);
    }
    foreach (var o in ps.Invoke())
    {
      stringBuilder.AppendLine(o.ToString());
    }
  }
  return stringBuilder.ToString();
}
  • Related