将参数从 C# 传递给被调用的 PowerShell 脚本 [英] Passing argument from C# to called PowerShell Script

查看:55
本文介绍了将参数从 C# 传递给被调用的 PowerShell 脚本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

private void RunScriptFile(string scriptPath, string computerName, PSCredential credential){RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();运行空间运行空间 = RunspaceFactory.CreateRunspace(runspaceConfiguration);运行空间.打开();RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);管道管道 = runspace.CreatePipeline();string scriptCommand = "Invoke-Command -ComputerName " + computerName + " -FilePath " + scriptPath + " -ArgumentList " + credential;管道.Commands.AddScript(scriptCommand);集合结果 = pipeline.Invoke();运行空间.关闭();}

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

Param([PSCredential]$Credentials)<使用凭证的代码部分>

pipeline.Invoke()之后,C#代码直接关闭,没有任何动作,也没有抛出任何错误.

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

Invoke-Command -ComputerName -文件路径<scipt.ps1>-ArgumentList " + 凭证;

解决方案

如果您将 .AddScript()self-contained 命令一起使用 - 似乎是 CommandCollection.AddScript() - 你只能以字符串形式嵌入参数,作为你的PowerShell代码片段的一部分重新传递 - 这不适用于 PSCredential 实例.

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

应用于您的场景:

private void RunScriptFile(string scriptPath, string computerName, PSCredential credential) {集合结果;使用 (var ps = PowerShell.Create()) {ps.AddCommand("调用命令").AddParameter("计算机名", 计算机名).AddParameter("文件路径", 脚本路径).AddParameter("ArgumentList", new object[] { credential })结果 = ps.Invoke();}}

这种方法的额外优势是不需要对 PowerShell 代码进行任何解析,因此速度更快、更可靠.

一般来说,使用 PowerShell 类可以简化 PowerShell SDK 的使用,并且在很多情况下就足够了(通常不需要管理运行空间、管道等).><小时>

但是,正如 PetSerAl 指出的那样,PowerShell.AddScript() 可以 接受类型参数,如果您通过 param(...)<重新制定代码片段以声明(类型化)参数/code> 块然后调用 .AddParameter()/.AddArgument():

ps.AddScript(@"param([string] $ComputerName, [string] $FilePath, [pscredential] $Credential) Invoke-Command -ComputerName $ComputerName -FilePath $FilePath -ArgumentList $Credential").AddArgument(计算机名).AddArgument(scriptPath).AddArgument(凭证)

然而,正如您所见,这使得解决方案更加冗长.

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

ps.AddScript(@"Invoke-Command -ComputerName $args[0] -FilePath $args[1] -ArgumentList $args[2]").AddArgument(计算机名).AddArgument(scriptPath).AddArgument(凭证)

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;

解决方案

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)

这篇关于将参数从 C# 传递给被调用的 PowerShell 脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆