问题
I have the following function in my C# file:
private void RunScriptFile(string scriptPath, string computerName, PSCredential credential)
{
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
Pipeline pipeline = runspace.CreatePipeline();
string scriptCommand = "Invoke-Command -ComputerName " + computerName + " -FilePath " + scriptPath + " -ArgumentList " + credential;
pipeline.Commands.AddScript(scriptCommand);
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
}
I am calling the following PowerShell script using Credentials passed in the above C# code; script.ps1
Param([PSCredential]$Credentials)
<code part using credentials>
After pipeline.Invoke()
, C# code just gets closed without any action, no errors are thrown too.
Is there something I am doing wrong while making the call? The same call if invoked from PowerShell like below works fine:
Invoke-Command -ComputerName <computerName> -FilePath <scipt.ps1> -ArgumentList " + credential;
回答1:
If you use .AddScript()
with a self-contained command - as is seemingly the only option with CommandCollection.AddScript() - you can only embed arguments in string form, as part of the PowerShell code snippet you're passing - and that won't work for a PSCredential
instance.
In order to pass arguments as specific .NET types in the context of a single command, you can instead use a PowerShell instance with the .AddCommand() and AddParameter() / AddArgument() methods.
Applied to your scenario:
private void RunScriptFile(string scriptPath, string computerName, PSCredential credential) {
Collection<PSObject> results;
using (var ps = PowerShell.Create()) {
ps.AddCommand("Invoke-Command")
.AddParameter("ComputerName", computerName)
.AddParameter("FilePath", scriptPath)
.AddParameter("ArgumentList", new object[] { credential })
results = ps.Invoke();
}
}
This approach has the added advantage of not requiring any parsing of PowerShell code, which is faster and more robust.
In general, use of the PowerShell
class simplifies use of the PowerShell SDK and is sufficient in many cases (often there is no need to manage runspaces, pipelines, ... explicitly).
However, as PetSerAl points out, PowerShell.AddScript() can accept typed arguments, if you reformulate the code snippet to declare (typed) parameters, via a param(...)
block and then call .AddParameter()
/ .AddArgument()
:
ps.AddScript(@"param([string] $ComputerName, [string] $FilePath, [pscredential] $Credential) Invoke-Command -ComputerName $ComputerName -FilePath $FilePath -ArgumentList $Credential")
.AddArgument(computerName)
.AddArgument(scriptPath)
.AddArgument(credential)
As you can see, however, that makes the solution more verbose.
Declaring parameters makes the intent more obvious, but you can alternatively use the automatic, array-valued $args
variable to access the arguments passed positionally:
ps.AddScript(@"Invoke-Command -ComputerName $args[0] -FilePath $args[1] -ArgumentList $args[2]")
.AddArgument(computerName)
.AddArgument(scriptPath)
.AddArgument(credential)
来源:https://stackoverflow.com/questions/57646703/passing-argument-from-c-sharp-to-called-powershell-script