Return object from PowerShell using a parameter ("By Reference" parameter)?

21,009

Solution 1

Ref should work, you don't say what happened when you tried it. Here is an example:

Test.ps1:

Param ([ref]$OptionalOutput)

"Standard output"
$OptionalOutput.Value = "Optional Output"

Run it:

$x = ""
.\Test.ps1 ([ref]$x)
$x

Here is an alternative that you might like better.

Test.ps1:

Param ($OptionalOutput)

"Standard output"
if ($OptionalOutput) {
    $OptionalOutput | Add-Member NoteProperty Summary "Optional Output"
}

Run it:

$x = New-Object PSObject
.\Test.ps1 $x
$x.Summary

Solution 2

Is this closer to what you want to do?

Test2.ps1

 $Issues = "Potentially long list of issues"
 $SummaryLine = "37 issues found"
 $Issues
 $SummaryLine

Test1.ps1

 $MainOutput,$SummaryOutput = & ".\Test2.ps1" 
 $MainOutput 
 $SummaryOutput

This:

 param([String]$SummaryLine)
 $Issues = "Potentially long list of issues"
 $SummaryLine = "37 issues found"
 $Issues

Is irrational. You're passing a parameter for $SummaryLine, and then immediatly replacing it with "37 issues found". That variable only exists in the scope the called script is running in. As soon as that script finishes, it's gone. If you want to use it later, you need to output it and save it to a variable in your calling script.

Share:
21,009
Mark Berry
Author by

Mark Berry

Updated on February 09, 2020

Comments

  • Mark Berry
    Mark Berry about 4 years

    I have one PowerShell (2.0) script calling another. I want to receive back not only the main output, but an additional object that I can use separately, e.g. to display a Summary Line in a message.

    Let's have Test2.ps1 as the script being called:

    param([String]$SummaryLine)
    $Issues = "Potentially long list of issues"
    $SummaryLine = "37 issues found"
    $Issues
    

    And Test1.ps1 as the script that calls it:

    $MainOutput = & ".\Test2.ps1" -SummaryLine $SummaryOutput
    $MainOutput
    $SummaryOutput
    

    The output is simply:

    Potentially long list of issues
    

    Although the parameter $SummaryLine is filled in by Test2, $SummaryOutput remains undefined in Test1.

    Defining $SummaryOutput before calling Test2 doesn't help; it just retains the value assigned before calling Test2.

    I've tried setting up $SummaryOutput and $SummaryLine as a [ref] variables (as one can apparently do with functions), but the $SummaryOutput.Value property is $null after calling Test2.

    Is it possible in PowerShell to return a value in a parameter? If not, what are the workarounds? Directly assigning a parent-scoped variable in Test2?

  • Mark Berry
    Mark Berry about 13 years
    Yes, I was trying to basically treat Test2 as a function with a "ByRef" (output) parameter. Your syntax comes pretty close. Multiple variables to the left of the = is new to me but I think I get it: Multi Variable Assignment. The only additional "feature" I'd like is to be able to call Test2 without seeing the $SummaryLine. In other words, the default would be to only return the $Issues detail. I guess for that I could pass a $ShowSummary boolean param and only output the $SummaryLine if $ShowSummary=True.
  • mjolinor
    mjolinor about 13 years
    I'd use a [switch] parameter, rather than a boolean.
  • Mark Berry
    Mark Berry about 13 years
    Holy cow, [ref] does work! When I tried that, I assigned $OptionalOutput rather than $OptionalOutput.Value inside the called script, so $x was not updated in the calling script. So what is going on in your second approach? If $x is a PSObject, it is automatically passed as [ref]?
  • JasonMArcher
    JasonMArcher about 13 years
    I would suggest using [ref] and not the second option. In PowerShell (as .NET), objects are passed by reference, but variables are scoped. That may be hard to understand at first, but it is true.
  • Mark Berry
    Mark Berry about 13 years
    @JasonMArcher: Yes, I like [ref] for being more explicit. Re. passing objects, if all objects are passed by reference, why doesn't that work for a String (which is a .NET Reference Type object)?
  • OldFart
    OldFart about 13 years
    In the [ref] example, $OptionalOutput is not a reference to the object, it is a reference to the variable $x. So you can actually change the value of the variable $x. In the Add-Member example, you are not changing which object $x references, you are changing the object itself. BTW, it doesn't have to be a PSObject, any object will do, but PSObject makes a good blank object.
  • JasonMArcher
    JasonMArcher about 13 years
    @Mark It is a reference, but strings are immutable so it may as well not be (except for using the PowerShell Type Extension system to add members).
  • MKesper
    MKesper about 8 years
    Beware though of casting issues and that you don't really pass a variable around but a PSReference object containing your variable as "Value" member.