2009-02-09 144 views
79

Necesito ejecutar un script de PowerShell desde C#. La secuencia de comandos necesita argumentos de línea de comandos.Ejecutar el script de PowerShell desde C# con los argumentos de la línea de comando

Esto es lo que he hecho hasta ahora:

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

el archivo de guión contiene algo así como "C: \ Archivos de programa \ MiPrograma \ Whatever.ps1".

La secuencia de comandos utiliza un argumento de línea de comandos como "-key Value", mientras que Value puede ser algo así como una ruta que también podría contener espacios.

No consigo que esto funcione. ¿Alguien sabe cómo pasar argumentos de línea de comandos a un script de PowerShell desde C# y asegurarse de que los espacios no sean un problema?

Respuesta

90

Trate de crear el archivo de guión con un comando aparte:

Command myCommand = new Command(scriptfile); 

continuación, puede añadir parámetros con

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

y finalmente

pipeline.Commands.Add(myCommand); 

Aquí está el código completo, editado:

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

todavía me parece que tienen el problema de que si el valor es algo así como c: \ archivos de programa \ miprograma, la clave se establece en C: \ Program. :( – Mephisztoe

+0

No importa. A veces ayuda cuando sabes cómo dividir cadenas correctamente ;-) Gracias de nuevo, ¡tu solución me ayudó a resolver mi problema! – Mephisztoe

+0

@Tronex - debe definir la clave como un parámetro para su secuencia de comandos. PowerShell tiene algunas excelentes herramientas integradas para trabajar con rutas. Quizás haga otra pregunta sobre eso. @ Kosi2801 tiene la respuesta correcta para agregar parámetros. –

4

Usted también puede utilizar la tubería con el Método 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; 

Se llevará a una cadena, y lo que los parámetros que se pasa.

7

¿Alguna posibilidad de obtener más claridad sobre el paso de params al método Commands.AddScript?

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

archivo_de_guión = "C: \ Foo1.PS1"

parámetros = "parm1 parm2 parm3" ... longitud variable de params

resuelto este ... que pasa NULL como el nombre y el parámetro como valor en una colección de CommandParameters

Aquí está mi función:

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

pasando nulo como el nombre ... esto fue muy útil –

+0

Acaba de agregar: 'using (Runspace runspace = RunspaceFactory.CreateRunspace (runspaceConfiguration)) ... usando (Pipeline pipeline = runspace.CreatePipeline())' – Red

3

Aquí es una manera de añadir parámetros al script si utilizó

pipeline.Commands.AddScript(Script); 

Esto es con el uso de un HashMap como Paramaters la clave es el nombre de la variable en la secuencia de comandos y el valor es el valor de la variable.

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

Y el relleno variable de método es:

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

esta manera se puede agregar fácilmente varios parámetros a un script. También he notado que si usted desea conseguir un valor de una variable en la que la escritura de este modo:

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

// resultados es el nombre de la v

Vas a tener que hacerlo de la de la forma en que lo mostré porque por alguna razón, si lo hace de la manera en que Kosi2801 sugiere que la lista de variables del script no se llene con sus propias variables.

21

Tengo otra solución. Solo quiero probar si la ejecución de un script de PowerShell es exitosa, porque tal vez alguien podría cambiar la política. Como argumento, solo especifico la ruta del script para ser ejecutado.

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 el contenido de la escritura de bienestar:

$someVariable = "StringToBeVerifiedInAUnitTest" 
$someVariable 
+1

Hola. ¿Tiene alguna idea de por qué no arranca PowerShell como lo describió y ejecuta todos los procesos (en nuestro caso)? –

+0

¿Qué biblioteca estás usando? – SoftwareSavant

2

Para mí, la forma más flexible para ejecutar secuencias de comandos PowerShell desde C# estaba usando PowerShell.Create() AddScript()

. El fragmento del código es

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

Puede verificar si hay algún error al verificar Streams.Error. Fue realmente útil para verificar la colección. El usuario es el tipo de objeto que devuelve el script de PowerShell.

2

mina es un poco más pequeño y más simple:

/// <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; 
} 
Cuestiones relacionadas