2

Why is the following changing type?

function SomeFunction($SomeParameter){
    return $SomeParameter
}

I guess I need to set a return type, but how?

An example is using:

$NewFolder=Join-Path $CurrentFolder -ChildPath $FolderName
$Tmp=SomeFunction($NewFolder)

Now $Tmp is an array and not just a path

Chris G.
  • 23,930
  • 48
  • 177
  • 302

2 Answers2

8

While this answer explains the behavior you're seeing, here I will attempt to answer the actual question: how to declare the expected output type of a function!

You do so by adding an [OutputType] attribute to the param() block of your function - so the first thing you'll want to do is to skip the C#-style param list and declare a proper param block instead:

function SomeFunction
{
    param($SomeParameter)

    return $SomeParameter
}

Now we just need to add the [OutputType] attribute decorator:

function SomeFunction
{
    [OutputType([string])]
    param($SomeParameter)

    return $SomeParameter
}

since we're just returning the parameter argument value as-is in this example, we should play nice and make sure it's actually also a string:

function SomeFunction
{
    [OutputType([string])]
    param(
        [string]$SomeParameter
    )

    return $SomeParameter
}

Worth noting that [OutputType()] makes no guarantees as to the type of objects emitted during execution, it's simply a way for the author of a function to indicate the intended output type.

Read more about [OutputType] in the about_Functions_OutputTypeAttribute help file

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • So one doesn't necessarily need to go read about the `OutputTypeAttribute` (though I do recommend checking it out, there are good nuggets of knowledge to be had!), all this attribute allows you to do is declare what your function is _expected_ to return, but it in no way _enforces_ that the value(s) returned by your function are of the declared type. So, IMO, this doesn't _really_ address the OP's question. The _real_ answer is that there is no way to specify that a function returns a specific type. (Note, I said function and not Cmdlet--the two are very different, the latter written in C#.) – fourpastmidnight Jul 10 '23 at 16:16
  • 1
    @fourpastmidnight My answer already covers that ("Worth noting that `[OutputType()]` makes no guarantees as to the type of objects emitted during execution, it's simply a way for the author of a function to indicate the intended output type."), but you're more than welcome to submit another answer if you feel the existing ones are insufficient :) – Mathias R. Jessen Jul 10 '23 at 16:19
  • Hmm, I see what you stated about "no guarantees", it's just, at the top, you made it sound like you were specifying a return type. I wanted to make it clear you are not specifying a return type, just _declaring_ that the function _should_ return the indicated type. I was just trying to clarify that this is only a _hint_, to users and (more properly) to PowerShell for IntelliSense, but that's all. Your answer, otherwise, is superb! In fact, I upvoted it because it is entirely correct (save that minor quibble I have ;) ) – fourpastmidnight Jul 10 '23 at 21:10
2

Your issue is per "design". PowerShell will return an array in chunks so that it can be forwarded the PowerShell pipeline.

Example:

 SomeFunction -SomeParameter @(1,2,3,4) | Where-Object { $_ -gt 2 }

Without this behavior pipelining the output of the function to another function/cmdlet won't be possible.

If you want to return an array you can change to code to:

 function SomeFunction($SomeParameter){
    <#
     # Through the unary operator we can return an array with one entry.
     # This entry contains the original array.
     #>
    ,$SomeParameter
}

Another option would be the use of @() when at the calling side:

function SomeFunction($SomeParameter){
    # return to pipelin
    $SomeParameter
}

$array = @(SomeFunction -SomeParameter 1,2,3,4)

There is also this reddit answer explaining the behavior in more detail.

Hope that helps.

Moerwald
  • 10,448
  • 9
  • 43
  • 83