How comes `if (Test-Path...)` actually works?
powershell, syntax
Solution
Referring to C.2.2 from Appendix C: The PowerShell grammar in Bruce Payette's Windows PowerShell in Action, we have:
<ifStatementRule> =
'if' '(' <pipelineRule> ')' <statementBlockRule>
[ 'elseif' '(' <pipelineRule> ')' <statementBlockRule> ]*
[ 'else' <statementBlockRule> ]{0|1}
This indicates the `(` and `)` tokens as part of the literal syntax for recognizing an `if` statement, and that the `<test>` from the `about_If` documentation refers to a pipeline that will be resolved to a Boolean.
Following the pipeline rules, we find:
- `Test-Path ...` parses to a `<cmdletCall>` of `<name> <parameterArgumentToken>`,
- `!Test-Path ...` results in an `<expressionRule>` of `<UnaryOperatorToken> <propertyOrArrayReferenceRule>`, which fails when the cmdlet call cannot match the simple property or array rule, whereas
- `!(Test-Path ...)` is able to match the parenthesized cmdlet call as a sub-expression.
Edit: See also PowerShell 2.0 Language Specification (thanks to Roman's answer to another question).
Problem
In PowerShell, syntax for `if` is as so: ``` if (<test1>) {<statement list 1>} [elseif (<test2>) {<statement list 2>}] [else {<statement list 3>}] ``` Another syntax rule is that for subexpressions, you need to use parentheses like this: ``` write-output (get-date) ``` So with these two rules combined, I would expect that the test for some path needs to be written with two sets of parentheses like this: ``` if ((Test-Path ...)) { # do something } ``` However, this also works: ``` if (Test-Path ...) { # do something } ``` and just for the sake of completeness, this doesn't work: ``` if (!Test-Path ...) { # do something } ``` (here, you would need to wrap the subexpression in parenthesis as usual). Can anyone explain the syntax rules that apply here and how comes that I can use the IF test with one parenthesis only? Is it some PowerShell magic or am I misunderstanding the basic syntax rules?