Esegui script PowerShell da C # con argomenti della riga di comando


101

Devo eseguire uno script PowerShell da C #. Lo script necessita di argomenti da riga di comando.

Questo è quello che ho fatto finora:

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 contiene qualcosa come "C: \ Program Files \ MyProgram \ Wutely.ps1".

Lo script utilizza un argomento della riga di comando come "-key Value" mentre Value può essere qualcosa di simile a un percorso che potrebbe contenere anche spazi.

Non riesco a farlo funzionare. Qualcuno sa come passare gli argomenti della riga di comando a uno script PowerShell da C # e assicurarsi che gli spazi non siano un problema?


1
Giusto per chiarire per i futuri utenti, la risposta accettata risolve il problema per le persone che hanno problemi con gli spazi anche senza i parametri di utilizzo. Utilizzando: Command myCommand = new Command(scriptfile);e quindi pipeline.Commands.Add(myCommand);risolvere il problema di fuga.
scharette

Risposte:


111

Prova a creare il file di script come comando separato:

Command myCommand = new Command(scriptfile);

quindi puoi aggiungere parametri con

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

e infine

pipeline.Commands.Add(myCommand);

Ecco il codice completo e modificato:

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

Mi sembra ancora di avere il problema che se il valore è qualcosa come c: \ program files \ myprogram, la chiave è impostata su c: \ program. :(
Mephisztoe,

Non importa. A volte aiuta quando sai come dividere correttamente le stringhe. ;-) Grazie ancora, la tua soluzione mi ha aiutato a risolvere il mio problema!
Mephisztoe

@Tronex: dovresti definire la chiave come parametro per il tuo script. PowerShell ha alcuni ottimi strumenti incorporati per lavorare con i percorsi. Forse fai un'altra domanda a riguardo. @ Kosi2801 ha la risposta corretta per l'aggiunta di parametri.
Steven Murawski,

Digitando la mia risposta si è sovrapposto alla tua .. Sono contento che tu abbia risolto!
Steven Murawski

1
La variabile scriptInvoker non viene utilizzata.
niaher

33

Ho un'altra soluzione. Voglio solo verificare se l'esecuzione di uno script PowerShell riesce, perché forse qualcuno potrebbe cambiare la politica. Come argomento, mi limito a specificare il percorso dello script da eseguire.

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

Con il contenuto dello script:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable

1
Ciao. Hai idea del perché l'avvio di PowerShell come hai descritto e l'esecuzione di tutti i comandi di processo (nel nostro caso) non si conclude?
Eugeniu Torica

Quale libreria stai utilizzando
SoftwareSavant

11

Ho avuto problemi a passare i parametri al metodo 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

Ho risolto questo problema passando nullcome nome e parametro come valore in una raccolta diCommandParameters

Ecco la mia funzione:

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

Appena aggiunto:using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))...using (Pipeline pipeline = runspace.CreatePipeline())
Rosso

Quando passo più parametri, si verifica questo errore: Un'eccezione non gestita di tipo "System.Management.Automation.ParseException" si è verificata in System.Management.Automation.dll
Muhammad Noman

5

Puoi anche usare la pipeline con il metodo 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;

Ci vorrà una stringa e qualunque parametro tu la passi.


4

Il mio è un po 'più piccolo e semplice:

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

Ecco un modo per aggiungere parametri allo script, se utilizzato

pipeline.Commands.AddScript(Script);

Questo avviene con l'utilizzo di una HashMap come parametri, la chiave è il nome della variabile nello script e il valore è il valore della variabile.

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

E il metodo della variabile di riempimento è:

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

in questo modo puoi facilmente aggiungere più parametri a uno script. Ho anche notato che se vuoi ottenere un valore da una variabile nel tuo script in questo modo:

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

// risulta essere il nome del v

dovrai farlo nel modo in cui ti ho mostrato perché per qualche motivo se lo fai nel modo in cui Kosi2801 suggerisce che l'elenco delle variabili di script non viene riempito con le tue variabili.


3

Per me, il modo più flessibile per eseguire lo script di PowerShell da C # era usare PowerShell.Create().AddScript()

Lo snippet del codice è

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

Puoi verificare se ci sono errori controllando Streams.Error. È stato davvero utile controllare la collezione. Utente è il tipo di oggetto restituito dallo script di PowerShell.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.