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