1

Why does PowerShell need a line continuation backtick after the first condition of the Where-Object scriptblock? It should be clear that the scriptblock has not yet ended as there has been no closing curly brace }.

Why does this work:

Get-Process | Where-Object {
    ($_.Responding -ne $true) `
    -or ($_.ProcessName -like 'W*')
}

and this doesn't:

Get-Process | Where-Object {
    ($_.Responding -ne $true)
    -or ($_.ProcessName -like 'W*')
}

This also fails.

Get-Process | Where-Object {
    (
        ($_.Responding -ne $true)
        -or ($_.ProcessName -like 'W*')
    )
}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
lit
  • 14,456
  • 10
  • 65
  • 119
  • 1
    PowerShell does know the script block hasn't ended, just check the `>>` prompt you get on the lines. But PowerShell can't "glue" the long boolean expression you've provided together without the continuation. Without the backtick it can't tell how you mean to split up a multiline statement. Multiple statements in one block are legal, after all. Try putting the `-or` on the line and then split and voila, it knows you're not done yet without a continuation. – Jeroen Mostert Oct 11 '16 at 15:15
  • @JeroenMostert - I agree that PowerShell knows the scriptblock has not ended. However, it would seem reasonable that if the next line begins with a boolean operator that it should be considered an extension of the boolean expression. Is that so unreasonable? – lit Oct 11 '16 at 15:28
  • 2
    It's quite unreasonable because you're demanding that the parser employ lookahead. `($_.Responding -ne $true)` is complete on its own. `-or` cannot *start* an expression, so either we need to backtrack when we see it by its own or we need to scan ahead at line end to make sure someone isn't trying to continue our line. ...of course, I'm thinking as an implementer now and not an end user. From an end user POV, this may be considered unreasonable, but it's a defensible kind of unreasonable. – Jeroen Mostert Oct 11 '16 at 15:30
  • @JeroenMostert - Thank you for acknowledging that the user may have a different perspective from the implementer. If you will make your post an answer, I will mark it so. – lit Oct 11 '16 at 15:39

1 Answers1

2

Your first example works, because you tell PowerShell that the statement is continued in the next line (by escaping the linebreak).

The other two examples fail, because the expression on the first line is a complete expression in and by itself, whereas the expression on the second line is not. PowerShell first evaluates ($_.Responding -ne $true), then tries to evaluate -or ($_.ProcessName -like 'W*'), which is an invalid statement and thus fails.

To avoid this you need to make it clear to the interpreter that the statement on the first line is continued in the next line. That can be done either by escaping the linebreak like you do in your first example:

Get-Process | Where-Object {
    ($_.Responding -ne $true) `
    -or ($_.ProcessName -like 'W*')
}

or by constructing your statement in a way that allows the interpreter to detect that there is more to come, e.g. by putting the operator at the end of the first line instead of at the beginning of the second line:

Get-Process | Where-Object {
    ($_.Responding -ne $true) -or
    ($_.ProcessName -like 'W*')
}

The curly braces can't be used to detect the end of the statement, because it's valid to put multiple statements in a Where-Object scriptblock.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328