function say2(){
$res = $false;
$arr = 1..10
$arr | ForEach-Object{
if($_ -eq 5){
$res = $true
break;
}
}
write-host "im here!"
return $res
}
$result = say2
write-host $result
why does the function 'say2' return null ? after the break, it seem to jump out the 'say2' function!!
Any response will be appreciated. thanks in advance.
Simple! Beside the fact that you are not displaying any results before the break then the value is gone as it never reaches the Write-Host line,
There's a couple of ways to tackle this:
function say2()
{
$res = $false;
$arr = 1 .. 10
$arr | ForEach-Object{
if ($_ -eq 5)
{
$res = $true
return
}
}
write-host "im here!"
return $res
}
say2
function say2()
{
$res = $false;
$arr = 1 .. 10
$arr | ForEach-Object{
if ($_ -eq 5)
{
$res = $true
write-host "im here! breaking = $res";
break
}
}
write-host "im here!"
return $res
}
say2
Sorry! Answer to your question: Yes! 'break' will terminate the function and all variables are discarded.
:)
@MaximoTrinidad It's extremely grateful to your response.
I know the execution order well, but I don't accept your answer.Look at the code below:
function say1(){
$arr = 1..10
$result = 0
foreach($item in $arr){
if($item -eq 5){
$result = 5
break
}
}
write-host "im here!"
return $result;
}
$result1 = say1
write-host $result1

Obviously after the break it executes the return , so it's not the break that terminates the function.
I guess the pipeline of foreach-object causes that weird result.I will search more materials to figure it out.
It's important to note the behavior of $arr | ForEach-Object{} and foreach($item in $arr){} are different.
When using Foreach-Object {} the, script block you supply is actually the positional parameter for the -Process parameter. When you use this method, the code acts like the Process{} block on an advanced function. The proper way to short-circuit a Process block is the return statement. When you use break in this context it actually affects whatever outer looping construct that is affected by break and not the Foreach-Object {} loop.
You can see it demonstrated here:
'Before Foreach'
foreach ($i in 1..5) {
'Before Foreach-Object {0}' -f $i
-2..$i | ForEach-Object {
'In Foreach-Object {0}' -f $_
if ($_ -eq 3) {
'Break from Foreach-Object {0}' -f $_
break
}
'After if in Foreach-Object {0}' -f $_
}
'After Foreach-Object {0}' -f $i
}
'After Foreach {0}' -f $i
The result:
Before Foreach
Before Foreach-Object 1
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
After Foreach-Object 1
Before Foreach-Object 2
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
In Foreach-Object 2
After if in Foreach-Object 2
After Foreach-Object 2
Before Foreach-Object 3
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
In Foreach-Object 2
After if in Foreach-Object 2
In Foreach-Object 3
Break from Foreach-Object 3
After Foreach 3
You can see that the After Foreach-Object 3 is never reached. and that the outer foreach ($i in $c){} loop is broken out of.
Compare that with this which uses return instead of break in the Foreach-Object {}:
'Before Foreach'
foreach ($i in 1..5) {
'Before Foreach-Object {0}' -f $i
-2..$i | ForEach-Object {
'In Foreach-Object {0}' -f $_
if ($_ -eq 3) {
'Break from Foreach-Object {0}' -f $_
return
}
'After if in Foreach-Object {0}' -f $_
}
'After Foreach-Object {0}' -f $i
}
'After Foreach {0}' -f $i
Result
Before Foreach
Before Foreach-Object 1
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
After Foreach-Object 1
Before Foreach-Object 2
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
In Foreach-Object 2
After if in Foreach-Object 2
After Foreach-Object 2
Before Foreach-Object 3
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
In Foreach-Object 2
After if in Foreach-Object 2
In Foreach-Object 3
Break from Foreach-Object 3
After Foreach-Object 3
Before Foreach-Object 4
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
In Foreach-Object 2
After if in Foreach-Object 2
In Foreach-Object 3
Break from Foreach-Object 3
In Foreach-Object 4
After if in Foreach-Object 4
After Foreach-Object 4
Before Foreach-Object 5
In Foreach-Object -2
After if in Foreach-Object -2
In Foreach-Object -1
After if in Foreach-Object -1
In Foreach-Object 0
After if in Foreach-Object 0
In Foreach-Object 1
After if in Foreach-Object 1
In Foreach-Object 2
After if in Foreach-Object 2
In Foreach-Object 3
Break from Foreach-Object 3
In Foreach-Object 4
After if in Foreach-Object 4
In Foreach-Object 5
After if in Foreach-Object 5
After Foreach-Object 5
After Foreach 5
Specifically this:
In Foreach-Object 3
Break from Foreach-Object 3
In Foreach-Object 4
Notice how that pattern then repeats. That is because only the Foreach-Object {} loop is being broken out of and the outer foreach ($i in $c){} loop continues to operate.
The confusing part in this is that Foreach is an alias of Foreach-Object but effectively Foreach ($I in $c){} is a different looping construct from Foreach-Object {}. continue and break should be used in Foreach ($i in $c){} and return should be used in Foreach-Object.
For background information on break and continue, see https://github.com/PowerShell/PowerShell/issues/3879#issuecomment-304940545.
To add to @markekraus's explanation: It's important to note that return in the ForEach-Object cmdlet's -Process block is the equivalent of continue inside a genuine looping construct such as foreach ($v in ...) { ... }.
By contrast, a genuine loop's break keyword has _no_ ForEach-Object equivalent; in other words: exiting the pipeline prematurely, on demand is not directly supported.
See https://github.com/PowerShell/PowerShell/issues/3879#issuecomment-304991572
@mklement0, Thanks for the explanation on the difference of foreach and foreach-object which doesn't behave the same way.
@guguji5, was just looking into foreach-object in your sample provided.
:)
@MaximoTrinidad @markekraus @mklement0 Thanks for your explanation.This issue leads me a deep understanding in powershell.
I change the foreach-object to the foreach and it works as I expect.
Most helpful comment
@mklement0, Thanks for the explanation on the difference of foreach and foreach-object which doesn't behave the same way.
@guguji5, was just looking into foreach-object in your sample provided.
:)