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 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; }
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.
To return multiple values from a PowerShell function, you can return an array of objects. The following example returns the multiple values from a function num using an array. Code: function num() { $a = 4,5,6 return $a } $b=num Write-Host "The numbers are $($b[0]),$($b[1]),$($b[2])."
The return keyword exits a function, script, or script block. It can be used to exit a scope at a specific point, to return a value, or to indicate that the end of the scope has been reached.
If you are inside of a function and return a value with the return keyword, the function will return that value and exit the function. The return keyword causes the function to exit after outputting the first process. PowerShell will then generate output for both processes.
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! :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With