web-dev-qa-db-fra.com

Exécuter un script PowerShell à partir de C # avec des arguments de ligne de commande

Je dois exécuter un script PowerShell à partir de C #. Le script nécessite des arguments en ligne de commande.

Voici ce que j'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", tandis que Value peut ressembler à un chemin contenant éventuellement des espaces.

Je ne comprends pas que ça marche. Quelqu'un sait-il comment passer des arguments de ligne de commande à un script PowerShell à partir de C # et s'assurer que les espaces ne posent aucun problème?

90
Mephisztoe

Essayez de créer un fichier de script en tant que commande séparée:

Command myCommand = new Command(scriptfile);

alors vous pouvez ajouter des paramètres avec

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

et enfin

pipeline.Commands.Add(myCommand);

Voici le code complet et édité:

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

J'ai une autre solution. Je souhaite simplement vérifier si l'exécution d'un script PowerShell aboutit, car une personne pourrait peut-être modifier la stratégie. En tant qu'argument, je spécifie simplement 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 du script étant:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable
29
Jowen

Toute chance je pourrais obtenir plus de clarté sur les paramètres de passage à la méthode Commands.AddScript?

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

scriptFile = "C:\Foo1.PS1"

parameters = "parm1 parm2 parm3" ... longueur variable des paramètres

Résolu ceci ... en passant à null comme nom et à param comme valeur 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();
}
9
twalker

Vous pouvez également simplement utiliser le pipeline avec la méthode 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;

Il faudra une chaîne, et quels que soient les paramètres que vous transmettez.

5
James Pogran

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

pipeline.Commands.AddScript(Script);

En utilisant un HashMap comme paramètre, la clé est 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 de la variable de remplissage est:

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

de 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 dans votre script, procédez comme suit:

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

// résultat étant le nom du v

vous devrez le faire comme je l'ai montré car pour une raison quelconque, si vous le faites comme Kosi2801 le suggère, la liste des variables de script ne se remplit pas avec vos propres variables.

3
Ruud

Pour moi, le moyen le plus flexible d'exécuter un script PowerShell à partir de C # était d'utiliser PowerShell.Create (). AddScript ()

Le fragment de 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 une erreur en vérifiant Streams.Error. C'était vraiment pratique de vérifier la collection. Utilisateur est le type d'objet renvoyé par le script PowerShell.

2
Andy

Le mien est un peu plus petit et 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;
}
2
Pedro Luz