2009-02-09 36 views
79

Tôi cần thực thi tập lệnh PowerShell từ bên trong C#. Kịch bản lệnh cần các đối số dòng lệnh.Thực thi PowerShell Script từ C# với các đố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 \ Whatever.ps1".

Tập lệnh sử dụng đối số dòng lệnh như "-key Value" trong khi Value có thể giống như một đường dẫn cũng có thể chứa dấu cách.

Tôi không làm việc này. Có ai biết làm thế nào để vượt qua các đối số dòng lệnh để một kịch bản PowerShell từ bên trong C# và đảm bảo rằng không gian là không có vấn đề?

Trả lời

90

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

Command myCommand = new Command(scriptfile); 

sau đó bạn có thể thêm các thông số với

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

và cuối cùng

pipeline.Commands.Add(myCommand); 

Dưới đây là hoàn chỉnh, mã 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(); 
+0

tôi vẫn dường như có vấn đề rằng nếu giá trị là cái gì đó như c: file \ program \ myprogram, chìa khóa được thiết lập để c: \ program. :( – Mephisztoe

+0

Đừng bận tâm, đôi khi nó giúp ích khi bạn biết cách phân chia chính xác các chuỗi .--) Cảm ơn bạ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

+0

@Tronex - bạn nên xác định khóa làm tham số cho tập lệnh của mình. PowerShell có một số công cụ dựng sẵn 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 đúng để thêm thông số. –

4

Bạn cũng có thể chỉ cần sử dụng đường ống 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ẽ mất một chuỗi, và bất cứ thông số bạn vượt qua nó.

7

Bất kỳ cơ hội nào tôi có thể hiểu rõ hơn về các tham số truyền cho phương thức Commands.AddScript?

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

scriptFile = "C: \ Foo1.PS1"

thông số = "parm1 parm2 parm3" ... biến chiều dài của params

Resolved này ... đi qua null như tên và param như giá trị vào một tập hợp các CommandParameters

đâ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(); 
} 
+0

truyền null là tên ... điều này rất hữu ích –

+0

Chỉ cần thêm: 'using (Runspace runspace = RunspaceFactory.CreateRunspace (runspaceConfiguration)) ... sử dụng (Pipeline pipeline = runspace.CreatePipeline())' – Red

3

Dưới đây là một cách để thêm thông số để kịch bản nếu bạn sử dụng

pipeline.Commands.AddScript(Script); 

Đây là với việc sử dụng một HashMap như paramaters chìa khóa là tên của biến trong kịch bản và giá trị là giá trị của biến.

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

Và điền biến phương pháp 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); 
    } 
    } 
} 

cách này bạn có thể dễ dàng thêm nhiều tham số để một kịch bản. Tôi cũng nhận thấy rằng nếu bạn muốn nhận được một giá trị từ một biến trong bạn kịch 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 điều đó cách tôi cho thấy bởi vì vì một lý do nào đó nếu bạn làm theo cách này, thì Kosi2801 gợi ý rằng danh sách các biến kịch bản không được lấp đầy với các biến của riêng bạn.

21

Tôi có một giải pháp khác. Tôi chỉ muốn thử nghiệm nếu thực hiện một kịch bản PowerShell thành công, bởi vì có lẽ ai đó có thể thay đổi chính sách. Là đối số, tôi chỉ xác định đường dẫn của tập lệnh được thực hiện.

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 các nội dung của kịch bản phúc:

$someVariable = "StringToBeVerifiedInAUnitTest" 
$someVariable 
+1

Xin chào. Bạn có bất kỳ ý tưởng tại sao bắt đầu PowerShell như bạn mô tả và thực hiện tất cả các quá trình lệnh (trong trường hợp của chúng tôi) không thoát? –

+0

Bạn đang sử dụng thư viện nào – SoftwareSavant

2

Đối với tôi, cách linh hoạt nhất để chạy kịch bản PowerShell từ C# được 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ề.

2

mỏ nhỏ hơn một chút và đơn giản hơn:

/// <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; 
} 
Các vấn đề liên quan