2009-02-09 10 views
79

Je dois exécuter un script PowerShell à partir de C#. Le script a besoin d'arguments de ligne de commande.Exécuter le script PowerShell à partir de C# avec les arguments de la ligne de commande

C'est ce que je l'ai fait jusqu'à présent:

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 contient quelque chose comme "C: \ Program Files \ MyProgram \ Whatever.ps1".

Le script utilise un argument de ligne de commande tel que "-key Value" alors que Value peut être quelque chose comme un chemin qui peut aussi contenir des espaces.

Je ne comprends pas cela. Est-ce que quelqu'un sait comment passer des arguments de ligne de commande à un script PowerShell à partir de C# et assurez-vous que les espaces ne posent aucun problème?

Répondre

90

Essayez de créer fichierscript comme une commande séparée:

Command myCommand = new Command(scriptfile); 

vous pouvez alors ajouter des paramètres avec

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

et enfin

pipeline.Commands.Add(myCommand); 

Voici le complet, le code modifié:

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

Il me semble encore avoir le problème que si la valeur est quelque chose comme c: \ program files \ myprogram, la clé est c: \ program. :( – Mephisztoe

+0

Peu importe, parfois cela aide quand vous savez comment séparer correctement les chaînes. ;-) Merci encore, votre solution m'a aidé à résoudre mon problème! – Mephisztoe

+0

@Tronex - vous devriez définir la clé comme étant un paramètre pour votre script. PowerShell a de bons outils intégrés pour travailler avec les chemins. Peut-être poser une autre question à ce sujet. @ Kosi2801 a la bonne réponse pour l'ajout de paramètres. –

4

Vous pouvez aussi utiliser le pipeline avec le addScript Méthode:

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; 

Il faudra une chaîne, et quel que soit les paramètres que vous passez.

7

Y a-t-il une chance que je puisse obtenir plus de clarté sur les paramètres de passage à la méthode Commands.AddScript?

C: \ Foo1.PS1 Bonjour faim dans le monde C: \ Foo2.PS1 Bonjour tout le monde

ScriptFile = "C: \ Foo1.PS1"

paramètres = "parm1 param2 parm3" ... longueur variable params

résolu ce ... passer null comme le nom et la valeur param dans une collection de CommandParameters

Voici ma fonction:

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

passant null comme le nom ... cela a été très utile –

+0

Juste ajouté: 'using (Runspace runspace = RunspaceFactory.CreateRunspace (runspaceConfiguration)) ... en utilisant (Pipeline pipeline = runspace.CreatePipeline())' – Red

3

est ici un moyen d'ajouter des paramètres au script si vous avez utilisé

pipeline.Commands.AddScript(Script); 

Ceci est à l'aide d'une table de hachage comme paramaters la clé étant le nom de la variable dans le script et la valeur est la valeur de la variable.

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

Et la méthode est variable de remplissage:

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

cette façon, vous pouvez facilement ajouter plusieurs paramètres à un script. J'ai aussi remarqué que si vous voulez obtenir une valeur d'une variable en vous script comme si:

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

// résultats étant le nom du v

que vous aurez à faire la comme je l'ai montré parce que pour une raison quelconque, si vous le faites de la façon Kosi2801 suggère que la liste des variables de script ne soit pas remplie avec vos propres variables.

21

J'ai une autre solution. Je veux juste tester si l'exécution d'un script PowerShell réussit, car peut-être que quelqu'un pourrait changer la politique. En tant qu'argument, je viens de spécifier le chemin du script à exécuter.

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

Avec le contenu de l'être de script:

$someVariable = "StringToBeVerifiedInAUnitTest" 
$someVariable 
+1

Salut. Avez-vous une idée pourquoi le démarrage de powershell comme vous l'avez décrit et l'exécution de toutes les commandes du processus (dans notre cas) ne se termine pas? –

+0

Quelle bibliothèque utilisez-vous? – SoftwareSavant

2

Pour moi, la façon la plus flexible pour exécuter le script PowerShell de C# utilisait PowerShell.Create() addScript()

. l'extrait du code est

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

Vous pouvez vérifier s'il y a des erreurs en vérifiant Streams.Error. C'était vraiment pratique pour vérifier la collection. L'utilisateur est le type d'objet renvoyé par le script PowerShell.

2

Le mien est un peu plus petit et plus 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; 
} 
Questions connexes