Thực thi PowerShell Script từ C # với đối số dòng lệnh


101

Tôi cần thực thi tập lệnh PowerShell từ bên trong C #. Tập lệnh cần đối số dòng lệnh.

Đây là những gì tôi đã làm cho đến nay:

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 chứa một cái gì đó như "C: \ Program Files \ MyProgram \ Anything.ps1".

Tập lệnh sử dụng một đối số dòng lệnh như "-key Value" trong khi Giá trị có thể là một cái gì đó giống như một đường dẫn cũng có thể chứa khoảng trắng.

Tôi không làm việc này. Có ai biết cách chuyển các đối số dòng lệnh vào tập lệnh PowerShell từ bên trong C # và đảm bảo rằng khoảng trắng không có vấn đề gì không?


1
Chỉ để làm rõ cho người dùng trong tương lai, câu trả lời được chấp nhận giải quyết vấn đề cho những người gặp vấn đề với khoảng trắng ngay cả khi không có thông số sử dụng. Sử dụng: Command myCommand = new Command(scriptfile);và sau đó pipeline.Commands.Add(myCommand);giải quyết vấn đề thoát.
scharette

Câu trả lời:


111

Hãy thử tạo scriptfile dưới dạng một lệnh riêng biệt:

Command myCommand = new Command(scriptfile);

thì bạn có thể thêm các tham số với

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

và cuối cùng

pipeline.Commands.Add(myCommand);

Đây là mã hoàn chỉnh, đã chỉnh sửa:

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

Tôi dường như vẫn gặp sự cố rằng nếu giá trị là một cái gì đó giống như c: \ program files \ myprogram, thì khóa được đặt thành c: \ program. :(
Mephisztoe 09/02/09

Đừng bận tâm. Đôi khi nó sẽ hữu ích khi bạn biết cách tách các chuỗi một cách chính xác. ;-) Cảm ơn một lần nữa, giải pháp của bạn đã giúp tôi giải quyết vấn đề của mình!
Mephisztoe

@Tronex - bạn nên xác định khóa là một tham số cho tập lệnh của mình. PowerShell có một số công cụ tích hợp tuyệt vời để làm việc với các đường dẫn. Có thể hỏi một câu hỏi khác về điều đó. @ Kosi2801 có câu trả lời chính xác cho việc thêm thông số.
Steven Murawski

Việc nhập câu trả lời của tôi trùng với câu trả lời của bạn .. Tôi rất vui vì bạn đã giải quyết được vấn đề này!
Steven Murawski

1
Biến scriptInvoker không được sử dụng.
niaher

33

Tôi có một giải pháp khác. Tôi chỉ muốn kiểm tra xem việc thực thi tập lệnh PowerShell có thành công hay không, vì có lẽ ai đó có thể thay đổi chính sách. Như đối số, tôi chỉ xác định đường dẫn của tập lệnh sẽ được thực thi.

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

Với nội dung của script là:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable

1
Chào. Bạn có biết tại sao khởi động powershell như bạn đã mô tả và quá trình thực thi tất cả các lệnh (trong trường hợp của chúng tôi) không thoát không?
Eugeniu Torica

Thư viện những gì bạn đang sử dụng
SoftwareSavant

11

Tôi đã gặp sự cố khi chuyển các tham số đến phương thức 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

Tôi đã giải quyết vấn đề này bằng cách chuyển nulldưới dạng tên và giá trị tham số vào một bộ sưu tậpCommandParameters

Đây là chức năng của tôi:

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

Vừa được thêm vào:using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))...using (Pipeline pipeline = runspace.CreatePipeline())
Red

Khi tôi đi qua nhiều tham số, nó xảy ra lỗi này: Một ngoại lệ unhandled của loại 'System.Management.Automation.ParseException' xảy ra ở System.Management.Automation.dll
Muhammad Noman

5

Bạn cũng có thể chỉ sử dụng đường dẫn với Phương pháp 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;

Nó sẽ lấy một chuỗi và bất kỳ tham số nào bạn truyền vào.


4

Của tôi nhỏ hơn và đơn giản hơn một chút:

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

Đây là một cách để thêm Tham số vào tập lệnh nếu bạn đã sử dụng

pipeline.Commands.AddScript(Script);

Điều này xảy ra với việc sử dụng HashMap làm paramaters, khóa là tên của biến trong script và giá trị là giá trị của biến.

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

Và phương pháp biến điền là:

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

bằng cách này, bạn có thể dễ dàng thêm nhiều tham số vào một tập lệnh. Tôi cũng nhận thấy rằng nếu bạn muốn nhận giá trị từ một biến trong tập lệnh của bạn như vậy:

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

// kết quả là tên của v

bạn sẽ phải làm theo cách tôi đã trình bày vì vì lý do nào đó nếu bạn làm theo cách Kosi2801 đề xuất thì danh sách các biến tập lệnh không được lấp đầy bằng các biến của riêng bạn.


3

Đối với tôi, cách linh hoạt nhất để chạy tập lệnh PowerShell từ C # là sử dụng PowerShell.Create().AddScript()

Đoạn mã là

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

Bạn có thể kiểm tra xem có lỗi nào không bằng cách kiểm tra Streams.Error. Nó thực sự tiện dụng để kiểm tra bộ sưu tập. Người dùng là loại đối tượng mà tập lệnh PowerShell trả về.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.