Komut Satırı Bağımsız Değişkenleriyle C # 'dan PowerShell Betiğini Yürütün


102

C # içinden bir PowerShell betiği yürütmem gerekiyor. Komut dosyası, komut satırı argümanlarına ihtiyaç duyar.

Şimdiye kadar yaptığım şey bu:

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 \ Programım \ Whatever.ps1" gibi bir şey içerir.

Komut dosyası, "-key Value" gibi bir komut satırı bağımsız değişkeni kullanır, oysa Değer, boşluklar da içerebilen bir yol gibi bir şey olabilir.

Bunu çalıştırmıyorum. C # içinden bir PowerShell betiğine komut satırı argümanlarının nasıl geçirileceğini bilen ve boşlukların sorun olmadığından emin olan var mı?


1
Sadece gelecekteki kullanıcılar için açıklığa kavuşturmak için kabul edilen cevap, kullanım parametreleri olmasa bile boşluklarla ilgili sorunları olan kişiler için sorunu çözer. Kullanarak: Command myCommand = new Command(scriptfile);ve ardından pipeline.Commands.Add(myCommand);kaçış sorununu çözün.
scharette

Yanıtlar:


112

Komut dosyası dosyasını ayrı bir komut olarak oluşturmayı deneyin:

Command myCommand = new Command(scriptfile);

daha sonra ile parametreler ekleyebilirsiniz

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

ve sonunda

pipeline.Commands.Add(myCommand);

İşte tam, düzenlenmiş kod:

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

Hala değer c: \ program files \ myprogram gibi bir şeyse, anahtarın c: \ program olarak ayarlanması sorunu yaşıyorum. :(
Mephisztoe

1
Boşver. Bazen dizeleri nasıl doğru şekilde ayıracağınızı bildiğiniz zaman yardımcı olur. ;-) Tekrar teşekkürler, çözümünüz sorunumu çözmeme yardımcı oldu!
Mephisztoe

@Tronex - anahtarı komut dosyanız için bir parametre olarak tanımlamalısınız. PowerShell, yollarla çalışmak için bazı harika yerleşik araçlara sahiptir. Belki bununla ilgili başka bir soru sorabilirsiniz. @ Kosi2801 parametre eklemek için doğru cevaba sahiptir.
Steven Murawski

Cevabımı yazmak seninkiyle örtüşüyordu .. Çözdüğüne sevindim!
Steven Murawski

2
scriptInvoker değişkeni kullanılmıyor.
niaher

33

Başka bir çözümüm var. Sadece bir PowerShell betiğinin başarılı olup olmadığını test etmek istiyorum, çünkü belki birileri politikayı değiştirebilir. Argüman olarak, sadece yürütülecek komut dosyasının yolunu belirtiyorum.

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

Komut dosyasının içeriği şu şekildedir:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable

1
Selam. Açıkladığınız gibi powershell'i başlatmanın ve tüm komut sürecini (bizim durumumuzda) yürütmenin neden çıkmadığına dair bir fikriniz var mı?
Eugeniu Torica

Hangi kitaplığı kullanıyorsunuz
SoftwareSavant

11

Parametreleri Commands.AddScript yöntemine aktarırken sorun yaşadım.

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

scriptFile = "C:\Foo1.PS1"

parameters = "parm1 parm2 parm3" ... variable length of params

Bunu null, ad olarak ve değer olarak param'ı bir koleksiyona geçirerek çözdüm.CommandParameters

İşte benim fonksiyonum:

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

Yeni eklendi:using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))...using (Pipeline pipeline = runspace.CreatePipeline())
Red

Birden çok parametreyi ilettiğimde şu hatayla karşılaşıyor: System.Management.Automation.dll'de 'System.Management.Automation.ParseException' türünde işlenmemiş bir istisna oluştu
Muhammad Noman

5

Ayrıca ardışık düzeni AddScript Yöntemi ile de kullanabilirsiniz:

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;

Bir dizge ve hangi parametreleri iletirseniz iletin.


4

Benimki biraz daha küçük ve daha basit:

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

Eğer kullandıysanız, betiğe Parametreler eklemenin bir yolu:

pipeline.Commands.AddScript(Script);

Bu, parametreler olarak bir HashMap kullanmaktır, anahtar koddaki değişkenin adıdır ve değer, değişkenin değeridir.

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

Ve dolgu değişkeni yöntemi:

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

bu şekilde bir betiğe birden çok parametreyi kolayca ekleyebilirsiniz. Ayrıca betiğinizdeki bir değişkenden bir değer elde etmek istiyorsanız şöyle olduğunu fark ettim:

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

// sonuç, v'nin adıdır

Bunu benim gösterdiğim şekilde yapmanız gerekecek çünkü bir nedenle Kosi2801'in komut dosyası değişkenleri listesinin kendi değişkenlerinizle doldurulmadığını öne sürdüğü şekilde yaparsanız.


3

Benim için PowerShell betiğini C # 'dan çalıştırmanın en esnek yolu kullanmaktı PowerShell.Create().AddScript()

Kod pasajı

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'ı kontrol ederek herhangi bir hata olup olmadığını kontrol edebilirsiniz. Koleksiyonu kontrol etmek gerçekten kullanışlıydı. Kullanıcı, PowerShell betiğinin döndürdüğü nesne türüdür.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.