How would I return an object or multiple values from PowerShell to executing C# code

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.

What is the right way to do that - in both Powershell and 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.

Answers


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

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

In C# code handle the Psobject in this way

 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 script:

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

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.

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:

$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:

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 StackOverflow post: https://stackoverflow.com/a/5577500

Where Kieren Johnstone says:

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


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.

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.


Need Your Help

Recurly returning "invalid data" for new subscription creation

php api payment-gateway credit-card recurly

The code below is what we're using to try and create a new subscription for a user. If the user doesn't already exist, we create them using createAccount before running createSubscription.

NSString to NSData conversion

ios nsstring nsdata

I am having following NSString: