如何将对象或多个值从PowerShell返回到执行C#代码

时间:2021-11-19 13:41:16

Some C# code executes a powershell script with arguments. I want to get a returncode and a string back from Powershell to know, if everything was ok inside the Powershell script.

一些C#代码使用参数执行powershell脚本。我想从Powershell获取一个返回码和一个字符串,以便知道Powershell脚本中是否一切正常。

What is the right way to do that - in both Powershell and C#

什么是正确的方法 - 在Powershell和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;
  }

I have managed to do this is some hacky ways by using Write-Output and relying on conventions like "last two psObjects are the values I am looking for", but it would break very easily.

我设法做到这一点是一些hacky方式使用Write-Output并依赖于“最后两个psObjects是我正在寻找的值”的约定,但它会很容易破坏。

3 个解决方案

#1


23  

In your powershell script you can build an Hashtable based on your necessity:

在您的powershell脚本中,您可以根据您的需要构建一个Hashtable:

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

In C# code handle the Psobject in this way

在C#代码中以这种方式处理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.

If you want to use a PsCustomobject as in Keith Hill comment in powershell v2.0:

如果你想在PowerShell v2.0中的Keith Hill评论中使用PsCustomobject:

powershell script:

powershell脚本:

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

c# code:

c#代码:

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

#2


5  

CB.'s answer worked great for me with a minor change. I did not see this posted anywhere (in regards to C# and PowerShell) so I wanted to post it.

CB。的答案对我来说很有意义,只有一点点变化。我没有看到这个贴在任何地方(关于C#和PowerShell)所以我想发布它。

In my PowerShell script I created created a Hashtable, stored 2 values in it (a Boolean and an Int) and then converted that into a PSObject:

在我的PowerShell脚本中,我创建了一个Hashtable,在其中存储了2个值(布尔值和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

And then in my C# code I did the same thing that CB. did but I had to use Convert.ToString in order to successfully get the values back:

然后在我的C#代码中,我做了与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;)
   }

I found the answer to this via the following * post: https://*.com/a/5577500

我通过以下*帖子找到了答案:https://*.com/a/5577500

Where Kieren Johnstone says:

Kieren Johnstone说:

Use Convert.ToDouble(value) rather than (double)value. It takes an object and supports all of the types you asked for! :)

使用Convert.ToDouble(value)而不是(double)值。它需要一个对象并支持您要求的所有类型! :)

#3


0  

Wow, good question! I'll take a shot off the top of my head...

哇,好问题!我会从头顶射击......

You could design a class in C# that represents the structure you want to use to pass data between the two. In the PS script, you could use an XmlWriter to craft an XML response and use Write-output to spit out the XML string.

您可以在C#中设计一个类,它表示您希望用于在两者之间传递数据的结构。在PS脚本中,您可以使用XmlWriter来制作XML响应并使用Write-output来吐出XML字符串。

On the C# side, capture the standard out response, deserialize the XML into your new response class, and then process the result. Note that you can't write anything out to stdout other than your XML response, or else you won't be able to deserialze into the class.

在C#端,捕获标准输出响应,将XM​​L反序列化为新的响应类,然后处理结果。请注意,除了XML响应之外,您不能向stdout写任何内容,否则您将无法反序列化到类中。

#1


23  

In your powershell script you can build an Hashtable based on your necessity:

在您的powershell脚本中,您可以根据您的需要构建一个Hashtable:

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

In C# code handle the Psobject in this way

在C#代码中以这种方式处理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.

If you want to use a PsCustomobject as in Keith Hill comment in powershell v2.0:

如果你想在PowerShell v2.0中的Keith Hill评论中使用PsCustomobject:

powershell script:

powershell脚本:

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

c# code:

c#代码:

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

#2


5  

CB.'s answer worked great for me with a minor change. I did not see this posted anywhere (in regards to C# and PowerShell) so I wanted to post it.

CB。的答案对我来说很有意义,只有一点点变化。我没有看到这个贴在任何地方(关于C#和PowerShell)所以我想发布它。

In my PowerShell script I created created a Hashtable, stored 2 values in it (a Boolean and an Int) and then converted that into a PSObject:

在我的PowerShell脚本中,我创建了一个Hashtable,在其中存储了2个值(布尔值和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

And then in my C# code I did the same thing that CB. did but I had to use Convert.ToString in order to successfully get the values back:

然后在我的C#代码中,我做了与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;)
   }

I found the answer to this via the following * post: https://*.com/a/5577500

我通过以下*帖子找到了答案:https://*.com/a/5577500

Where Kieren Johnstone says:

Kieren Johnstone说:

Use Convert.ToDouble(value) rather than (double)value. It takes an object and supports all of the types you asked for! :)

使用Convert.ToDouble(value)而不是(double)值。它需要一个对象并支持您要求的所有类型! :)

#3


0  

Wow, good question! I'll take a shot off the top of my head...

哇,好问题!我会从头顶射击......

You could design a class in C# that represents the structure you want to use to pass data between the two. In the PS script, you could use an XmlWriter to craft an XML response and use Write-output to spit out the XML string.

您可以在C#中设计一个类,它表示您希望用于在两者之间传递数据的结构。在PS脚本中,您可以使用XmlWriter来制作XML响应并使用Write-output来吐出XML字符串。

On the C# side, capture the standard out response, deserialize the XML into your new response class, and then process the result. Note that you can't write anything out to stdout other than your XML response, or else you won't be able to deserialze into the class.

在C#端,捕获标准输出响应,将XM​​L反序列化为新的响应类,然后处理结果。请注意,除了XML响应之外,您不能向stdout写任何内容,否则您将无法反序列化到类中。