Reputation: 51
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
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
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