将参数从 C# 传递到调用的 PowerShell 脚本

spo*_*993 5 c# powershell powershell-sdk

我的 C# 文件中有以下函数:

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();
}
Run Code Online (Sandbox Code Playgroud)

我使用上面 C# 代码中传递的凭据调用以下 PowerShell 脚本;脚本.ps1

Param([PSCredential]$Credentials)
<code part using credentials>
Run Code Online (Sandbox Code Playgroud)

之后pipeline.Invoke(),C# 代码只是关闭,没有任何操作,也不会抛出任何错误。

我在拨打电话时是否做错了什么?如果从 PowerShell 调用相同的调用,如下所示,则可以正常工作:

Invoke-Command -ComputerName <computerName> -FilePath <scipt.ps1> -ArgumentList " +  credential;
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 4

.AddScript()如果与自包含 命令一起使用,则必须以字符串形式嵌入参数,作为您传递的 PowerShell 代码片段的一部分 - 这对于实例不起作用PSCredential

为了在单个命令的上下文中将参数作为特定 .NET 类型传递,您可以使用PowerShell带有 .AddCommand()and AddParameter()/AddArgument()方法的实例。

适用于您的场景:

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的另一个优点是不需要对 PowerShell 代码进行任何解析,速度更快、更稳健。

一般来说,使用该类PowerShell可以简化 PowerShell SDK 的使用,并且在许多情况下就足够了(通常不需要显式管理运行空间、管道等)。


但是,正如PetSerAl指出的那样,如果您重新编写代码片段以通过块声明(类型化)参数,然后调用/ ,则可以接受类型化参数PowerShell.AddScript() param(...).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)
Run Code Online (Sandbox Code Playgroud)

然而,正如您所看到的,这使得解决方案更加冗长。

声明参数使意图更加明显,但您也可以使用自动数组值变量来访问按位置$args传递的参数

ps.AddScript(@"Invoke-Command -ComputerName $args[0] -FilePath $args[1] -ArgumentList $args[2]")
  .AddArgument(computerName)
  .AddArgument(scriptPath)
  .AddArgument(credential)
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • 此答案提供有关在 C# 应用程序中使用哪个 NuGet 包的指导,具体取决于主机应用程序和/或目标 PowerShell 版本。

  • 本答案介绍了如何在使用 PowerShell SDK 的上下文中处理错误。