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

使用命令行参数从C#执行PowerShell脚本,c#,command-line,powershell,scripting,arguments,C#,Command Line,Powershell,Scripting,Arguments,我需要从C#中执行PowerShell脚本。脚本需要命令行参数 这就是我到目前为止所做的: RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create(); Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration); runspace.Open(); RunspaceInvoke scriptInvoker = n

我需要从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();
脚本文件包含类似“C:\Program Files\MyProgram\Whatever.ps1”的内容

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


我不能让它工作。有人知道如何从C#中向PowerShell脚本传递命令行参数并确保空格没有问题吗?

尝试将scriptfile作为单独的命令创建:

Command myCommand = new Command(scriptfile);
然后可以使用添加参数

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

pipeline.Commands.Add(myCommand);

以下是完整的编辑代码:


您也可以将管道与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;
string cmdArg=“。\script.ps1-foo-bar”
收集结果;
使用(管道管道=\u运行空间.CreatePipeline())
{
pipeline.Commands.AddScript(cmdArg);
pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error,PipelineResultTypes.Output);
psresults=pipeline.Invoke();
}
返回结果;

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

我在向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();
}
private static void runpowershell脚本(字符串脚本文件、字符串脚本参数)
{
RunspaceConfiguration RunspaceConfiguration=RunspaceConfiguration.Create();
Runspace Runspace=RunspaceFactory.CreateRunspace(runspaceConfiguration);
Open();
RunspaceInvoke scriptInvoker=新的RunspaceInvoke(运行空间);
Pipeline Pipeline=runspace.CreatePipeline();
命令scriptCommand=新命令(脚本文件);
Collection commandParameters=new Collection();
foreach(scriptParameters.Split(“”)中的字符串scriptParameter)
{
CommandParameter commandParm=新CommandParameter(null,scriptParameter);
commandParameters.Add(commandParm);
scriptCommand.Parameters.Add(commandParm);
}
pipeline.Commands.Add(scriptCommand);
对象集合;
psObjects=pipeline.Invoke();
}

如果您使用

pipeline.Commands.AddScript(Script);
这与使用HashMap作为参数有关,键是脚本中变量的名称,值是变量的值

pipeline.Commands.AddScript(script));
FillVariables(pipeline, scriptParameter);
Collection<PSObject> results = pipeline.Invoke();
通过这种方式,您可以轻松地向脚本添加多个参数。我还注意到,如果希望从脚本中的变量中获取值,如下所示:

Object resultcollection = runspace.SessionStateProxy.GetVariable("results");
//结果是v的名称

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

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

对我来说,从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);
string scriptDirectory=Path.GetDirectoryName(
ConfigurationManager.AppSettings[“路径工具”];
变量脚本=
“设置位置”+scriptDirectory+Environment.NewLine+
“导入模块。\\script.psd1”+Environment.NewLine+
“$data=导入Csv-Path”+tempCsvFile+“-Encoding UTF8”+
环境新线+
“新注册-服务器”+dbServer+“-DBName”+DBName+
“-Username\”“+user.Username+”\“+-Users$userData”;
_powershell=powershell.Create().AddScript(脚本);
_powershell.Invoke();
foreach(在_powershell.Streams.Error中的var errorRecord)
控制台写入线(错误记录);
您可以通过检查Streams.error来检查是否存在任何错误。检查藏品真的很方便。
用户是PowerShell脚本返回的对象类型。

我的对象更小、更简单:

/// <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;
}
//
///运行PowerShell脚本,获取其路径和参数。
/// 
///.ps1文件的完整文件路径。
///脚本的参数可以为null。
///PowerShell执行的输出。
公共静态ICollection运行脚本(字符串scriptFullPath,ICollection参数=null)
{
var runspace=RunspaceFactory.CreateRunspace();
Open();
var pipeline=runspace.CreatePipeline();
var cmd=新命令(scriptFullPath);
if(参数!=null)
{
foreach(参数中的var p)
{
cmd.Parameters.Add(p);
}
}
pipeline.Commands.Add(cmd);
var results=pipeline.Invoke();
pipeline.Dispose();
Dispose();
返回结果;
}

我似乎仍然有一个问题,即如果值类似于c:\program files\myprogram,则密钥设置为c:\program.:(没关系。有时,当你知道如何正确分割字符串时,它会有所帮助。-)再次感谢,你的解决方案帮助我解决了我的问题@Tronex-您应该将密钥定义为脚本的参数。PowerShell有一些很棒的用于处理路径的内置工具。也许可以问另一个问题@Kosi2801对于添加参数有正确的答案。未使用scriptInvoker变量。如何在c#back中捕获powershell输出。在我的示例中,pipeline.Invoke()如果ps script.Hi中有任何写入主机,则返回null值。您知道为什么按照您所描述的那样启动powershell并执行所有命令进程(在我们的例子中)不会退出吗?您使用的库刚刚添加:
using(Runspace Runspace=RunspaceFactory.CreateRunspace(runspaceConfiguration))…using
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);
/// <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;
}