Jalankan Skrip PowerShell dari C # dengan Argumen Baris Perintah

101

Saya perlu menjalankan skrip PowerShell dari dalam C #. Skrip membutuhkan argumen baris perintah.

Inilah yang telah saya lakukan sejauh ini:

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 berisi sesuatu seperti "C: \ Program Files \ MyProgram \ What's.ps1".

Skrip menggunakan argumen baris perintah seperti "-key Value" sedangkan Value bisa berupa jalur yang juga mungkin berisi spasi.

Saya tidak mendapatkan ini untuk bekerja. Adakah yang tahu cara meneruskan argumen baris perintah ke skrip PowerShell dari dalam C # dan memastikan bahwa spasi tidak menjadi masalah?

Mephisztoe
sumber
1
Hanya untuk memperjelas bagi pengguna di masa mendatang, jawaban yang diterima menyelesaikan masalah bagi orang-orang yang memiliki masalah dengan spasi bahkan tanpa parameter penggunaan. Menggunakan: Command myCommand = new Command(scriptfile);dan kemudian pipeline.Commands.Add(myCommand);menyelesaikan masalah pelarian.
scharette

Jawaban:

111

Coba buat scriptfile sebagai perintah terpisah:

Command myCommand = new Command(scriptfile);

lalu Anda dapat menambahkan parameter dengan

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

dan akhirnya

pipeline.Commands.Add(myCommand);

Ini kode lengkap yang diedit:

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();
Kosi2801
sumber
Saya masih memiliki masalah jika nilainya adalah seperti c: \ program files \ myprogram, kuncinya disetel ke c: \ program. :(
Mephisztoe
Lupakan. Terkadang membantu saat Anda mengetahui cara membagi string dengan benar. ;-) Sekali lagi terima kasih, solusi Anda membantu saya dalam menyelesaikan masalah saya!
Mephisztoe
@Tronex - Anda harus menetapkan kunci sebagai parameter untuk skrip Anda. PowerShell memiliki beberapa alat bawaan yang hebat untuk bekerja dengan jalur. Mungkin menanyakan pertanyaan lain tentang itu. @ Kosi2801 memiliki jawaban yang benar untuk menambahkan parameter.
Steven Murawski
Mengetik balasan saya tumpang tindih dengan jawaban Anda .. Saya senang Anda menyelesaikannya!
Steven Murawski
1
Variabel scriptInvoker tidak digunakan.
niaher
33

Saya punya solusi lain. Saya hanya ingin menguji apakah menjalankan skrip PowerShell berhasil, karena mungkin seseorang mungkin mengubah kebijakan. Sebagai argumennya, saya hanya menentukan path script yang akan dieksekusi.

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

Dengan isi naskahnya:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable
Jowen
sumber
1
Hai. Apakah Anda tahu mengapa memulai PowerShell seperti yang Anda jelaskan dan menjalankan semua proses perintah (dalam kasus kami) tidak keluar?
Eugeniu Torica
Perpustakaan apa yang Anda gunakan
SoftwareSavant
11

Saya mengalami masalah saat mengirimkan parameter ke metode 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

Saya menyelesaikan ini dengan mengirimkan nullnama dan param sebagai nilai ke dalam kumpulanCommandParameters

Inilah fungsi saya:

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();
}
penguntit
sumber
Baru saja menambahkan:using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))...using (Pipeline pipeline = runspace.CreatePipeline())
Merah
Ketika saya melewati beberapa parameter, itu terjadi kesalahan ini: Pengecualian tidak tertangani dari jenis 'System.Management.Automation.ParseException' terjadi di System.Management.Automation.dll
Muhammad Noman
5

Anda juga dapat menggunakan pipeline dengan Metode 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;

Ini akan mengambil string, dan parameter apa pun yang Anda berikan.

James Pogran
sumber
4

Milik saya sedikit lebih kecil dan sederhana:

/// <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;
}
Pedro Luz
sumber
3

Berikut adalah cara untuk menambahkan Parameter ke skrip jika Anda menggunakan

pipeline.Commands.AddScript(Script);

Ini dengan menggunakan HashMap sebagai parameter kunci menjadi nama variabel dalam skrip dan nilainya adalah nilai variabel.

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

Dan metode variabel isi adalah:

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

dengan cara ini Anda dapat dengan mudah menambahkan beberapa parameter ke skrip. Saya juga memperhatikan bahwa jika Anda ingin mendapatkan nilai dari variabel di skrip Anda seperti ini:

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

// hasilnya adalah nama v

Anda harus melakukannya seperti yang saya tunjukkan karena untuk beberapa alasan jika Anda melakukannya dengan cara Kosi2801 menyarankan daftar variabel skrip tidak diisi dengan variabel Anda sendiri.

Ruud
sumber
3

Bagi saya, cara paling fleksibel untuk menjalankan skrip PowerShell dari C # adalah menggunakan PowerShell.Create().AddScript()

Potongan kodenya adalah

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

Anda dapat memeriksa apakah ada kesalahan dengan memeriksa Streams.Error. Sangat berguna untuk memeriksa koleksinya. Pengguna adalah tipe objek yang dikembalikan skrip PowerShell.

Andy
sumber