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

jjjwad0x  于 2022-12-23  发布在  Shell
关注(0)|答案(1)|浏览(122)

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

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

Param([PSCredential]$Credentials)
<code part using credentials>

pipeline.Invoke()之后,C#代码只是被关闭,没有任何操作,也没有抛出错误。
我在调用时做错了什么吗?如果从PowerShell调用相同的调用,如下所示,可以正常工作:

Invoke-Command -ComputerName <computerName> -FilePath <scipt.ps1> -ArgumentList " +  credential;
6pp0gazn

6pp0gazn1#

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

为了在 * 单个命令*的上下文中 * 将参数 * 作为特定. NET类型 * 传递,您可以使用PowerShell示例和.AddCommand()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();
  }
}

这种方法还有一个额外的优点,即不需要对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)

但是,正如您所看到的,这使得解决方案更加冗长。
声明参数的意图更加明显,但是您可以使用自动的、数组值的$args变量来访问 * 位置*传递的参数:

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

另见:

  • This answer,以获得有关在C#应用程序中使用什么NuGet包的指导,具体取决于主机应用程序和/或目标PowerShell版本。
  • This answer,了解如何在使用PowerShell SDK的上下文中处理错误

相关问题