web-dev-qa-db-fra.com

Comment renvoyer un objet ou plusieurs valeurs de PowerShell à l'exécution de code C #

Certains codes C # exécutent un script PowerShell avec des arguments. Je veux obtenir un code de retour et une chaîne de retour de Powershell pour savoir si tout va bien dans le script Powershell. 

Quelle est la bonne façon de faire cela - à la fois dans Powershell et C #

Powershell

# Powershell script
# --- Do stuff here ---
# Return an int and a string - how?
# In c# I would do something like this, if this was a method:

# class ReturnInfo
# {
#    public int ReturnCode;
#    public string ReturnText;
# }

# return new ReturnInfo(){ReturnCode =1, ReturnText = "whatever"};

C #

void RunPowershellScript(string scriptFile, List<string> parameters)
    {

        RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

        using (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 parameters)
            {
                CommandParameter commandParm = new CommandParameter(null, scriptParameter);
                commandParameters.Add(commandParm);
                scriptCommand.Parameters.Add(commandParm);
            }
            pipeline.Commands.Add(scriptCommand);
            Collection<PSObject> psObjects;
            psObjects = pipeline.Invoke();

            //What to do here?
            //ReturnInfo returnInfo = pipeline.DoMagic();

        }
    }

  class ReturnInfo
  {
      public int ReturnCode;
      public string ReturnText;
  }

J'ai réussi à faire cela en utilisant des méthodes d'écriture-sortie utilisant des conventions telles que "les deux derniers psObjects sont les valeurs que je recherche", mais cela casserait facilement.

31
Kjensen

Dans votre script PowerShell, vous pouvez créer une table de hachage en fonction de vos besoins:

[hashtable]$Return = @{} 
$Return.ReturnCode = [int]1 
$Return.ReturnString = [string]"All Done!" 
Return $Return 

En code C #, gérez le psobject de cette manière

 ReturnInfo ri = new ReturnInfo();
 foreach (PSObject p in psObjects)
 {
   Hashtable ht = p.ImmediateBaseObject as Hashtable;
   ri.ReturnCode = (int)ht["ReturnCode"];
   ri.ReturnText = (string)ht["ReturnString"];
 } 

//Do what you want with ri object.

Si vous souhaitez utiliser un PsCustomobject comme dans le commentaire Keith Hill dans powershell v2.0:

script PowerShell:

$return = new-object psobject -property @{ReturnCode=1;ReturnString="all done"}
$return

c # code:

ReturnInfo ri = new ReturnInfo();
foreach (PSObject p in psObjects)
   {
     ri.ReturnCode = (int)p.Properties["ReturnCode"].Value;
     ri.ReturnText = (string)p.Properties["ReturnString"].Value;
   }
26
CB.

La réponse de CB. a bien fonctionné pour moi avec un changement mineur. Je ne l'ai pas vu nulle part (en ce qui concerne C # et PowerShell), donc je voulais le poster.

Dans mon script PowerShell, j'ai créé un tableau de hachage, y a stocké deux valeurs (un booléen et un int), puis l'a converti en un PSObject:

$Obj = @{}

if($RoundedResults -ilt $Threshold)
{
    $Obj.bool = $true
    $Obj.value = $RoundedResults
}
else
{
    $Obj.bool = $false
    $Obj.value = $RoundedResults
}

$ResultObj = (New-Object PSObject -Property $Obj)

return $ResultObj

Et puis dans mon code C #, j'ai fait la même chose que CB. ai fait mais je devais utiliser Convert.ToString afin de récupérer les valeurs:

ReturnInfo ri = new ReturnInfo();
foreach (PSObject p in psObjects)
   {
     ri.ReturnCode = Convert.ToBoolean(p.Properties["ReturnCode"].Value;)
     ri.ReturnText = Convert.ToString(p.Properties["ReturnString"].Value;)
   }

J'ai trouvé la réponse à cela via le message StackOverflow suivant: https://stackoverflow.com/a/5577500

Où Kieren Johnstone dit:

Utilisez Convert.ToDouble (valeur) plutôt que (double) valeur. Il faut un objet et prend en charge tous les types que vous avez demandé! :)

5
hvaughan3

Wow, bonne question! Je vais me prendre une balle dans la tête ...

Vous pouvez concevoir une classe en C # qui représente la structure que vous souhaitez utiliser pour transmettre des données entre les deux. Dans le script PS, vous pouvez utiliser XmlWriter pour créer une réponse XML et utiliser Write-output pour cracher la chaîne XML.

Du côté C #, capturez la réponse standard, désérialisez le code XML dans votre nouvelle classe de réponses, puis traitez le résultat. Notez que vous ne pouvez rien écrire sur stdout autre que votre réponse XML, sinon vous ne pourrez pas désérialiser dans la classe.

0
mgnoonan