เรียกใช้สคริปต์ PowerShell จาก C # ด้วย Commandline Arguments


102

ฉันต้องการเรียกใช้สคริปต์ PowerShell จากภายใน C # สคริปต์ต้องการอาร์กิวเมนต์บรรทัดคำสั่ง

นี่คือสิ่งที่ฉันได้ทำไปแล้ว:

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 อาจเป็นบางอย่างเช่นเส้นทางที่อาจมีช่องว่าง

ฉันไม่ได้ทำงานนี้ ไม่มีใครรู้วิธีส่งอาร์กิวเมนต์บรรทัดคำสั่งไปยังสคริปต์ PowerShell จากภายใน C # และตรวจสอบให้แน่ใจว่าช่องว่างไม่มีปัญหา?


1
เพื่อเป็นการชี้แจงสำหรับผู้ใช้ในอนาคตคำตอบที่ได้รับการยอมรับจะช่วยแก้ปัญหาสำหรับผู้ที่มีปัญหาเกี่ยวกับช่องว่างแม้ว่าจะไม่มีพารามิเตอร์การใช้งานก็ตาม ใช้: Command myCommand = new Command(scriptfile);แล้วpipeline.Commands.Add(myCommand);แก้ปัญหาการหลบหนี
scharette

คำตอบ:


112

ลองสร้าง scriptfile เป็นคำสั่งแยก:

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

ฉันยังคงมีปัญหาว่าถ้า value เป็น c: \ program files \ myprogram คีย์จะถูกตั้งค่าเป็น c: \ program :(
Mephisztoe

1
ไม่เป็นไร. บางครั้งอาจช่วยได้เมื่อคุณรู้วิธีแยกสตริงอย่างถูกต้อง ;-) ขอขอบคุณอีกครั้งโซลูชันของคุณช่วยฉันในการแก้ไขปัญหาของฉัน!
Mephisztoe

@Tronex - คุณควรกำหนดคีย์ว่าเป็นพารามิเตอร์สำหรับสคริปต์ของคุณ PowerShell มีเครื่องมือในตัวที่ยอดเยี่ยมสำหรับการทำงานกับพา ธ อาจถามคำถามอื่นเกี่ยวกับเรื่องนี้ @ Kosi2801 มีคำตอบที่ถูกต้องสำหรับการเพิ่มพารามิเตอร์
Steven Murawski

การพิมพ์คำตอบของฉันซ้อนทับคุณ .. ฉันดีใจที่คุณแก้ไขได้!
Steven Murawski

2
ไม่ได้ใช้ตัวแปร scriptInvoker
niaher

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.ParseException' เกิดขึ้นใน System.Management.Automation.dll
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

สำหรับฉันวิธีที่ยืดหยุ่นที่สุดในการเรียกใช้สคริปต์ PowerShell จาก C # คือการใช้ 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 ส่งกลับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.