【问题标题】:Execute PowerShell Script from C# with Commandline Arguments使用命令行参数从 C# 执行 PowerShell 脚本
【发布时间】:2010-10-06 08:45:24
【问题描述】:

我需要在 C# 中执行一个 PowerShell 脚本。该脚本需要命令行参数。

这是我到目前为止所做的:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();

RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);

Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.Add(scriptFile);

// Execute PowerShell script
results = pipeline.Invoke();

scriptFile 包含类似“C:\Program Files\MyProgram\Whatever.ps1”的内容。

脚本使用命令行参数,例如“-key Value”,而 Value 可以是类似路径的东西,也可能包含空格。

我没有让这个工作。有谁知道如何从 C# 中将命令行参数传递给 PowerShell 脚本并确保空格没有问题?

【问题讨论】:

  • 只是为了向未来的用户澄清,接受的答案解决了即使没有使用参数也有空间问题的人的问题。使用:Command myCommand = new Command(scriptfile); 然后pipeline.Commands.Add(myCommand); 解决转义问题。

标签: c# command-line powershell scripting arguments


【解决方案1】:

尝试将脚本文件创建为单独的命令:

Command myCommand = new Command(scriptfile);

然后你可以添加参数

CommandParameter testParam = new CommandParameter("key","value");
myCommand.Parameters.Add(testParam);

最后

pipeline.Commands.Add(myCommand);

这是完整的编辑代码:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();

Pipeline pipeline = runspace.CreatePipeline();

//Here's how you add a new script with arguments
Command myCommand = new Command(scriptfile);
CommandParameter testParam = new CommandParameter("key","value");
myCommand.Parameters.Add(testParam);

pipeline.Commands.Add(myCommand);

// Execute PowerShell script
results = pipeline.Invoke();

【讨论】:

  • 我似乎仍然有这样的问题,如果 value 类似于 c:\program files\myprogram,则 key 设置为 c:\program。 :(
  • 没关系。有时,当您知道如何正确拆分字符串时,它会有所帮助。 ;-) 再次感谢,您的解决方案帮助我解决了我的问题!
  • @Tronex - 您应该将密钥定义为脚本的参数。 PowerShell 有一些很棒的内置工具来处理路径。也许问另一个问题。 @Kosi2801 有添加参数的正确答案。
  • scriptInvoker 变量没有被使用。
  • 如何在 c# 中捕获 powershell 输出。在我的情况下 pipeline.Invoke() 如果 ps 脚本中有任何写入主机,则返回 null 值。
【解决方案2】:

我有另一个解决方案。我只想测试执行 PowerShell 脚本是否成功,因为也许有人可能会更改策略。作为参数,我只是指定要执行的脚本的路径。

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = @"powershell.exe";
startInfo.Arguments = @"& 'c:\Scripts\test.ps1'";
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();

string output = process.StandardOutput.ReadToEnd();
Assert.IsTrue(output.Contains("StringToBeVerifiedInAUnitTest"));

string errors = process.StandardError.ReadToEnd();
Assert.IsTrue(string.IsNullOrEmpty(errors));

脚本的内容是:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable

【讨论】:

  • 嗨。您是否知道为什么按照您的描述启动 powershell 并执行所有命令进程(在我们的例子中)不退出?
  • 你用的是什么库
【解决方案3】:

我在将参数传递给 Commands.AddScript 方法时遇到问题。

C:\Foo1.PS1 Hello World Hunger
C:\Foo2.PS1 Hello World

scriptFile = "C:\Foo1.PS1"

parameters = "parm1 parm2 parm3" ... variable length of params

我通过将null 作为名称并将参数作为值传递到CommandParameters 的集合中解决了这个问题

这是我的功能:

private static void RunPowershellScript(string scriptFile, string scriptParameters)
{
    RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
    Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
    runspace.Open();
    RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
    Pipeline pipeline = runspace.CreatePipeline();
    Command scriptCommand = new Command(scriptFile);
    Collection<CommandParameter> commandParameters = new Collection<CommandParameter>();
    foreach (string scriptParameter in scriptParameters.Split(' '))
    {
        CommandParameter commandParm = new CommandParameter(null, scriptParameter);
        commandParameters.Add(commandParm);
        scriptCommand.Parameters.Add(commandParm);
    }
    pipeline.Commands.Add(scriptCommand);
    Collection<PSObject> psObjects;
    psObjects = pipeline.Invoke();
}

【讨论】:

  • 刚刚添加:using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))...using (Pipeline pipeline = runspace.CreatePipeline())
  • 当我传递多个参数时,会出现此错误:System.Management.Automation.dll 中发生“System.Management.Automation.ParseException”类型的未处理异常
【解决方案4】:

我的更小更简单:

/// <summary>
/// Runs a PowerShell script taking it's path and parameters.
/// </summary>
/// <param name="scriptFullPath">The full file path for the .ps1 file.</param>
/// <param name="parameters">The parameters for the script, can be null.</param>
/// <returns>The output from the PowerShell execution.</returns>
public static ICollection<PSObject> RunScript(string scriptFullPath, ICollection<CommandParameter> parameters = null)
{
    var runspace = RunspaceFactory.CreateRunspace();
    runspace.Open();
    var pipeline = runspace.CreatePipeline();
    var cmd = new Command(scriptFullPath);
    if (parameters != null)
    {
        foreach (var p in parameters)
        {
            cmd.Parameters.Add(p);
        }
    }
    pipeline.Commands.Add(cmd);
    var results = pipeline.Invoke();
    pipeline.Dispose();
    runspace.Dispose();
    return results;
}

【讨论】:

    【解决方案5】:

    您也可以只使用带有 AddScript 方法的管道:

    string cmdArg = ".\script.ps1 -foo bar"            
    Collection<PSObject> psresults;
    using (Pipeline pipeline = _runspace.CreatePipeline())
                {
                    pipeline.Commands.AddScript(cmdArg);
                    pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
                    psresults = pipeline.Invoke();
                }
    return psresults;
    

    它将接受一个字符串,以及您传递给它的任何参数。

    【讨论】:

      【解决方案6】:

      对我来说,从 C# 运行 PowerShell 脚本最灵活的方法是使用 PowerShell.Create().AddScript()

      代码的sn-p是

      string scriptDirectory = Path.GetDirectoryName(
          ConfigurationManager.AppSettings["PathToTechOpsTooling"]);
      
      var script =    
          "Set-Location " + scriptDirectory + Environment.NewLine +
          "Import-Module .\\script.psd1" + Environment.NewLine +
          "$data = Import-Csv -Path " + tempCsvFile + " -Encoding UTF8" + 
              Environment.NewLine +
          "New-Registration -server " + dbServer + " -DBName " + dbName + 
             " -Username \"" + user.Username + "\" + -Users $userData";
      
      _powershell = PowerShell.Create().AddScript(script);
      _powershell.Invoke<User>();
      foreach (var errorRecord in _powershell.Streams.Error)
          Console.WriteLine(errorRecord);
      

      您可以通过检查 Streams.Error 来检查是否有任何错误。检查收藏真的很方便。 User 是 PowerShell 脚本返回的对象类型。

      【讨论】:

        【解决方案7】:

        如果您使用过,这里有一种向脚本添加参数的方法

        pipeline.Commands.AddScript(Script);
        

        这是使用 HashMap 作为参数,键是脚本中变量的名称,值是变量的值。

        pipeline.Commands.AddScript(script));
        FillVariables(pipeline, scriptParameter);
        Collection<PSObject> results = pipeline.Invoke();
        

        而填充变量的方法是:

        private static void FillVariables(Pipeline pipeline, Hashtable scriptParameters)
        {
          // Add additional variables to PowerShell
          if (scriptParameters != null)
          {
            foreach (DictionaryEntry entry in scriptParameters)
            {
              CommandParameter Param = new CommandParameter(entry.Key as String, entry.Value);
              pipeline.Commands[0].Parameters.Add(Param);
            }
          }
        }
        

        通过这种方式,您可以轻松地将多个参数添加到脚本中。我还注意到,如果您想从脚本中的变量中获取值,如下所示:

        Object resultcollection = runspace.SessionStateProxy.GetVariable("results");
        

        //结果是v的名字

        你必须按照我展示的方式去做,因为出于某种原因,如果你这样做 Kosi2801 建议脚本变量列表没有填充您自己的变量。

        【讨论】:

          【解决方案8】:

          这对我有用,包括参数包含空格的情况:

          using (PowerShell PowerShellInst = PowerShell.Create())
                  {
          
                      PowerShell ps = PowerShell.Create();
                      
                      string param1= "my param";
                      string param2= "another param";
                      string scriptPath = <path to script>;
          
                      ps.AddScript(File.ReadAllText(scriptPath));
          
                      ps.AddArgument(param1);
                      ps.AddArgument(param2);
          
                      ps.Invoke();
                   
                  }
          

          我觉得这种方法很容易理解,也很清楚。

          【讨论】:

            猜你喜欢
            • 2016-01-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多