简体   繁体   中英

Passing parameters from c# to powershell script

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, DC 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();
    }

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

What you're trying to pass are positional (unnamed) arguments, ie 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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM