2009-02-09 12 views
79

Ho bisogno di eseguire uno script PowerShell da C#. Lo script richiede argomenti della riga di comando.Esegui script PowerShell da C# con argomenti Commandline

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

FileScript contiene qualcosa come "C: \ Programmi \ Programma \ Whatever.ps1".

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

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

risposta

90

Prova a creare file di script come un comando separato:

Command myCommand = new Command(scriptfile); 

quindi è possibile aggiungere i parametri con

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

e infine

pipeline.Commands.Add(myCommand); 

Ecco il codice a cura completo:

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

mi sembrano ancora avere il problema che se il valore è qualcosa come c: \ programmi \ myprogram, la chiave è impostato su C: \ Program. :( – Mephisztoe

+0

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

+0

@Tronex - dovresti definire la chiave come parametro per il tuo script. PowerShell ha alcuni grandi strumenti integrati per lavorare con i percorsi. Forse fai un'altra domanda al riguardo. @ Kosi2801 ha la risposta corretta per l'aggiunta di parametri. –

4

È anche possibile utilizzare 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 tutto ciò che i parametri si passa.

7

Ogni possibilità di ottenere maggiore chiarezza sui parametri che passano al metodo Commands.AddScript?

C: \ Foo1.PS1 Ciao fame nel mondo C: \ Foo2.PS1 Ciao Mondo

FileScript = "C: \ Foo1.PS1"

parametri = "parm1 parm2 Parm3" ... lunghezza variabile params

risolto questo ... passando null come il nome e il parametro come valore in una collezione di CommandParameters

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

passando null come nome ... questo è stato molto utile –

+0

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

3

Ecco un modo per aggiungere parametri allo script se è stato utilizzato

pipeline.Commands.AddScript(Script); 

Questo è con l'utilizzo di un HashMap come paramaters 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 variabile il riempimento metodo è:

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

questo modo è possibile aggiungere facilmente più parametri a uno script. Ho anche notato che se si vuole ottenere un valore da una variabile in voi scritto in questo modo:

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

// risultati essere il nome del v

Dovrete farlo nel modo che ho mostrato perché per qualche ragione se lo fai il modo in cui lo Kosi2801 suggerisce che l'elenco delle variabili di script non si riempia delle tue stesse variabili.

21

Ho un'altra soluzione. Voglio solo verificare se l'esecuzione di uno script di PowerShell ha esito positivo, perché forse qualcuno potrebbe cambiare la politica. Come argomento, ho solo specificato 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 dell'essere script:

$someVariable = "StringToBeVerifiedInAUnitTest" 
$someVariable 
+1

Ciao. Hai idea del motivo per cui l'avvio di PowerShell durante la descrizione e l'esecuzione di tutti i comandi (nel nostro caso) non esce? –

+0

Che libreria stai usando – SoftwareSavant

2

Per me, il modo più flessibile per eseguire PowerShell script da C# stava usando PowerShell.Create() AddScript()

. il frammento 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); 

è possibile controllare se c'è qualche errore verificando Streams.Error. È stato davvero utile controllare la collezione. L'utente è il tipo di oggetto restituito dallo script PowerShell.

2

Il mio è un po 'più piccolo e più 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; 
} 
Problemi correlati