45

In a script I have several functions that need to break down an SVN external definition. These can either be <url> <path>, -r<rev> <url> <path>, or -r <rev> <url> <path>, and the mechanics I came up with to extract the data is more than just two lines, so I want to put this into a separate function.

But when I do so, I end up with three variables containing the relevant data which are local to the function, and I see no way to get all three of them them to the caller.

In a proper programming language I would return a compound type containing all three values, but I don't see how to do that in Powershell. Of course, I could split this into three separate functions, but then I am back at violating the DRY rule.

So what can I do here in Powershell?

0

6 Answers 6

108

I agree with @Christian, and I add another solution.

First you can return using an array explicitly or implicitly:

  1. explicitly

    function ExplicitArray ()
    {
      $myArray = @()
    
      $myArray += 12
      $myArray += "Blue"
    
      return ,$myArray
    }
    
    Clear-Host
    $a = ExplicitArray
    Write-Host "values from ExplicitArray are $($a[0]) and $($a[1])"
    
  2. implicitly

    function ImplicitArray ()
    {
      Write-Output 12
    
      Write-Output "Blue"
      return "green"
    }
    
    $b = ImplicitArray
    Write-Host "values from ImplicitArray are $($b[0]), $($b[1]) and $($b[2])"
    

Second you can return a custom object:

  1. Short form

    function ReturnObject ()
    {
      $value = "" | Select-Object -Property number,color
      $value.Number = 12
      $value.color = "blue"
      return $value
    }
    $c = ReturnObject
    Write-Host "values from ReturnObject are $($c.number) and $($c.color)"
    
  2. School form

    function SchoolReturnObject ()
    {
      $value = New-Object PsObject -Property @{color="blue" ; number="12"}
      Add-Member -InputObject $value –MemberType NoteProperty –Name "Verb" –value "eat"
      return $value
    }
    $d = SchoolReturnObject
    Write-Host "values from SchoolReturnObject are $($d.number), $($d.color) and $($d.Verb)"
    

Third using argument by reference:

function addition ([int]$x, [int]$y, [ref]$R)
{
 $Res = $x + $y
 $R.value = $Res
}

$O1 = 1
$O2 = 2
$O3 = 0
addition $O1 $O2 ([ref]$O3)
Write-Host "values from addition $o1 and $o2 is $o3"
Sign up to request clarification or add additional context in comments.

9 Comments

Ah, you can pass arguments by reference! I didn't know that. Thanks!
Note that it isn't necessary to use the return statements in the examples above. return in PowerShell is typically only used to alter the normal exit point from a function.
This is your point of view, I respect it. My point of view is that return $value make the function code more readable, moreover in my code I quite never use the Write-Output in a function. I exists old rules about structured programmation, that I try to apply
@JPBlanc: Thanks for this comprehensive answer. I have accepted the other answer, thouqh, because Christian was first, and I ended up doing what he suggested (using a custom object).
Can anyone explain why you need the comma in return ,$myArray. Coming from languages other than PowerShell I don't see why that comma is needed (although through testing I agree it is!)
|
55

Maybe I am misunderstanding the question but isn't this just as simple as returning a list of variables, and the caller simply assigns each to a variable. That is

> function test () {return @('a','c'),'b'}
> $a,$b = test

$a will be an array, and $b the letter 'b'

> $a 
a
c
> $b
b

2 Comments

Underrated answer. This is definitely the cleanest solution.
Be careful if your test() function generates any non-captured output before the return call, like New-Item d. This would screw up the variable assignment to $a,$b.
5

You can return an array of [string] and then let the caller split it or return a custom object and always the caller do the split.

3 Comments

Oh, that custom object thing looks exactly like what I need!
An example is missing here, which would be useful.
2

I was using a tuple to return multiple values but it had unexpected results vp_field1,vp_field2=abc()

so I refactored the code to:

function abc()
{
   $value = New-Object PsObject -Property @{ 
        vp_field1 = $field1;
        vp_field2 = $field2;
        }

    return $value;
}

$value=abc();

print("$value.vp_field1 $value.vp_field2")

Comments

0

You can cast a hashtable to a PSCustomObject and return that.

[PSCustomObject]@{First = 1; Second = 2; Third = 3}

Comments

0

I was looking how to call function/ class method and found this.

@eythort answered about functions, here is for method, where you need to define type.

If I understand question, issue is how to call

$a,$b = $C.test()

or

$a,$b = [C]::test()

I wrote this as

class C {
  static [System.Array] test () {
    return @('a','c'),'b'
  }
}

$a will be an array, and $b the letter 'b'

> $a
a
c
> $b
b

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.