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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/527513/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 06:49:48  来源:igfitidea点击:

Execute PowerShell Script from C# with Commandline Arguments

c#command-linepowershellscriptingarguments

提问by Mephisztoe

I need to execute a PowerShell script from within C#. The script needs commandline arguments.

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

This is what I have done so far:

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

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 contains something like "C:\Program Files\MyProgram\Whatever.ps1".

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

The script uses a commandline argument such as "-key Value" whereas Value can be something like a path that also might contain spaces.

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

I don't get this to work. Does anyone know how to pass commandline arguments to a PowerShell script from within C# and make sure that spaces are no problem?

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

采纳答案by Kosi2801

Try creating scriptfile as a separate command:

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

Command myCommand = new Command(scriptfile);

then you can add parameters with

然后你可以添加参数

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

and finally

最后

pipeline.Commands.Add(myCommand);


Here is the complete, edited code:

这是完整的,经过编辑的代码:

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

回答by James Pogran

You can also just use the pipeline with the AddScript Method:

您也可以只使用带有 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;

It will take a string, and whatever parameters you pass it.

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

回答by twalker

I had trouble passing parameters to the Commands.AddScript method.

我无法将参数传递给 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

I Resolved this by passing nullas the name and the param as value into a collection of CommandParameters

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

Here is my function:

这是我的功能:

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

回答by Ruud

Here is a way to add Parameters to the script if you used

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

pipeline.Commands.AddScript(Script);

This is with using an HashMap as paramaters the key being the name of the variable in the script and the value is the value of the variable.

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

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

And the fill variable method is:

而填充变量方法是:

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

this way you can easily add multiple parameters to a script. I've also noticed that if you want to get a value from a variable in you script like so:

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

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

//results being the name of the v

//results是v的名字

you'll have to do it the way I showed because for some reason if you do it the way Kosi2801 suggests the script variables list doesn't get filled with your own variables.

你必须按照我展示的方式来做,因为出于某种原因,如果你按照 Kosi2801 建议的方式来做,脚本变量列表不会被你自己的变量填充。

回答by Jowen

I have another solution. I just want to test if executing a PowerShell script succeeds, because perhaps somebody might change the policy. As the argument, I just specify the path of the script to be executed.

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

With the contents of the script being:

脚本的内容是:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable

回答by Andy

For me, the most flexible way to run PowerShell script from C# was using PowerShell.Create().AddScript()

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

The snippet of the code is

代码片段是

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

You can check if there's any error by checking Streams.Error. It was really handy to check the collection. User is the type of object the PowerShell script returns.

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

回答by Pedro Luz

Mine is a bit more smaller and simpler:

我的更小更简单:

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