Как я могу вернуть объект или несколько значений из PowerShell для выполнения кода С#

Некоторые С# код выполняет скрипт powershell с аргументами. Я хочу получить код возврата и строку обратно из Powershell, чтобы знать, если все в порядке внутри сценария Powershell.

Каков правильный способ сделать это - как в Powershell, так и в С#

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

С#

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

Мне удалось сделать это из-за хакерских способов, используя Write-Output и полагаясь на соглашения, такие как "последние два psObjects - это значения, которые я ищу", но это очень легко ломается.

Ответ 1

В сценарии powershell вы можете создать Hashtable, основываясь на вашей необходимости:

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

В коде С# обрабатывать Psobject таким образом

 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.

Если вы хотите использовать PsCustomobject, как в комментарии Keith Hill в powershell v2.0:

сценарий powershell:

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

Код С#:

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

Ответ 2

CB. Ответ работал отлично для меня с небольшими изменениями. Я не видел, чтобы это было опубликовано где угодно (в отношении С# и PowerShell), поэтому я хотел опубликовать его.

В моем сценарии PowerShell я создал созданную Hashtable, сохранил в ней 2 значения (Boolean и Int), а затем преобразовал их в 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

И тогда в моем коде С# я сделал то же самое, что и CB. но мне пришлось использовать Convert.ToString, чтобы успешно вернуть значения:

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

Я нашел ответ на этот вопрос через следующую публикацию StackOverflow: fooobar.com/questions/158736/...

Где Кирэн Джонстоун говорит:

Используйте Convert.ToDouble (значение), а не (двойное) значение. Он берет объект и поддерживает все типы, которые вы просили! :)

Ответ 3

Ничего себе, хороший вопрос! Я сделаю снимок с головы...

Вы можете создать класс на С#, который представляет структуру, которую вы хотите использовать для передачи данных между ними. В сценарии PS вы можете использовать XmlWriter для обработки ответа XML и использовать Write-output для Write-output строки XML.

На стороне С# запишите стандартный ответ, десериализуйте XML в свой новый класс ответа, а затем обработайте результат. Обратите внимание, что вы не можете ничего писать в stdout, кроме вашего ответа XML, иначе вы не сможете deserialze в классе.