romeo.Do
romeo.Do

Reputation: 51

Powershell returns wrong result

I came across this weird issue in Powershell (not in other languages). Could anyone please explain to me why this happened?

I tried to return a specified number (number 8), but the function keeps throwing everything at me. Is that a bug or by design?

Function GetNum() {
   Return 10
}

Function Main() {

    $Number10 = GetNum
    $number10 #1 WHY NO OUTPUT HERE ??????? I don't want to use write host
    $result = 8  # I WANT THIS NUMBER ONLY
    PAUSE
    return $result
}

do {    
    $again = Main
    Write-Host "RESULT IS "$again # Weird Result, I only want Number 8
} While ($again -eq 10) # As the result is wrong, it loops forever

Upvotes: 2

Views: 2645

Answers (2)

briantist
briantist

Reputation: 47862

Mathias is spot on as usual.

I want to address this comment in your code:

$number10 #1 WHY NO OUTPUT HERE ??????? I don't want to use write host

Why don't you want to use Write-Host? Is it because you may have come across this very popular post from PowerShell's creator with the provocative title Write-Host Considered Harmful?

If so, I encourage you to read what I think is a great follow-up/companion piece by tby, titled Is Write-Host Really Harmful?

With this information, it should be clear that as Mathias said, you are returning objects to the pipeline, but you should also be armed with the information needed to choose an alternative, whether it's Write-Verbose, Write-Debug, or even Write-Host.

If I were going to be opinionated about it, I would go with Write-Verbose, altering your function definition slightly in order to support it:

function Main {
[CmdletBinding()]
param()

    $Number10 = GetNum
    Write-Verbose -Message $number10 
    $result = 8  # I WANT THIS NUMBER ONLY
    PAUSE
    $result
}

When you invoke it by just calling $again = Main you'll see nothing on the screen, and $again will have a value of 8. However if you call it this way:

$again = Main -Verbose

then $again will still have the value of 8, but on the screen you'll see:

VERBOSE: 10

likely in differently colored text.

What that gives is not only a way to show the value, but a way for the caller to control whether they see the value or not, without changing the return value of the function.

To drive some of the points in the articles home further, consider that it's not necessarily necessary to invoke your function with -Verbose to get that.

For example, let's say you stored that whole script in a file called FeelingNum.ps1.

If, in addition to the changes I made above, you also add the following to the very top of your file:

[CmdletBinding()]
param()

Then, you still invoked your function "normally" as $again = Main, you could still get the verbose output by invoking your script with -Verbose:

powershell.exe -File FeelingNum.ps1 -Verbose

What happens there is that using the -Verbose parameter sets a variable called $VerbosePreference, and that gets inherited on each function called down the stack (unless it's overridden). You can also set $VerbosePreference manually.

So what you get by using these built-in features is a lot of flexibility, both for you as the author and for anyone who uses your code, which is a good thing even if the only person using it is you.

Upvotes: 4

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174865

Is that a bug or by design?

By design. In PowerShell, cmdlets can return a stream of objects, much like using yield return in C# to return an IEnumerable collection.

The return keyword is not required for output values to be returned, it simply exits (or returns from) the current scope.

From Get-Help about_Return (emphasis added):

    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.


    Users who are familiar with languages like C or C# might want to use the
    Return keyword to make the logic of leaving a scope explicit.


    In Windows PowerShell, the results of each statement are returned as
    output, even without a statement that contains the Return keyword.
    Languages like C or C# return only the value or values that are specified
    by the Return keyword.

Upvotes: 7

Related Questions