使用命令行参数从C#执行PowerShell脚本


101

我需要从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脚本并确保空格没有问题?


1
只是为了向将来的用户说明,接受的答案可以解决即使没有使用参数也有空间问题的人们的问题。使用:Command myCommand = new Command(scriptfile);然后pipeline.Commands.Add(myCommand);解决转义问题。
scharette

Answers:


111

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

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();

RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);

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();

我似乎仍然有一个问题,如果值类似于c:\ program files \ myprogram,则密钥设置为c:\ program。:(
Mephisztoe

没关系。有时,当您知道如何正确分割字符串时,它会有所帮助。;-)再次感谢您的解决方案,帮助我解决了我的问题!
Mephisztoe

@Tronex-您应该将密钥定义为脚本的参数。PowerShell具有一些很棒的内置工具来处理路径。也许问另一个问题。@ Kosi2801具有添加参数的正确答案。
史蒂芬·穆拉斯基

输入我的答复与您的答复重叠。.很高兴您解决了它!
史蒂芬·穆拉斯基

1
未使用scriptInvoker变量。
niaher 2014年

33

我有另一个解决方案。我只想测试执行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

1
你好 您是否知道为什么启动如您所描述的Powershell并执行所有命令进程(在我们的情况下)不会退出?
Eugeniu Torica

您正在使用什么库
SoftwareSavant

11

我在将参数传递给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'的未处理异常
Muhammad Noman

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;

它需要一个字符串,以及您传递的任何参数。


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;
}

3

如果您使用过以下方法,则可以使用以下方法将参数添加到脚本中

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的建议这样做,则脚本变量列表中不会包含您自己的变量。


3

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

该代码段是

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来检查是否有任何错误。检查收藏确实很方便。用户是PowerShell脚本返回的对象类型。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.