In a Param() block, blank line after a comment (sometimes) causes unexpected ParserError #21109
Replies: 4 comments 2 replies
-
Unlike classic UNIX shells, PowerShell really does not work well with scripts piped in as stdin. I believe this is a known issue. The following is my interpretation which may or may not be right; When you run a normal script I believe that PowerShell parses the whole file for syntax before it runs it, eg if I have a script
It complains about the missing curly brace and does not run the Write-Host command. However if I pipe that in as stdin to pwsh
It does execute the Write-Host statement So my theory is that when processing stdin it assumes the input is from a user and expects to execute each command once it is entered in its entirety. Normally it uses PSReadLine to read multi-line statements and deal with continuation, I cannot tell if PSReadLine is being used to process the input, I suggest not because the text is not syntax coloured when it is echoed to the console. If you pipe a script into a normal shell it does not echo the script to the stdout because it knows that stdin is not a tty and the input has not been typed. However in the case of PowerShell I believe pwsh is trying to process the input as if in an interactive session but without PSReadLine and in that case it is assuming the end of a multi line statement when it get an empty line. |
Beta Was this translation helpful? Give feedback.
-
By "known issue" I mean "it does not work so don't try and do it, issue" |
Beta Was this translation helpful? Give feedback.
-
If you want to pass a script in to pwsh to run then I suggest pass it as a single parameter
otherwise pass it as a single line as stdin, but then you still get the interactive prompts and the commands being echoed
Setting "-NonInteractive" makes no difference to the prompts |
Beta Was this translation helpful? Give feedback.
-
Dear @rhubarb-geek-nz: It is interesting to see another example (yours) of a snippet that behaves differently, with respect to whether it generates an error, when piped into pwsh stdin as compared with other ways of executing the snippet. However, curiously, your snippet has exactly the opposite behavior from mine, as demonstrated below. I suspect that the difference in behavior between your snippet and mine is due to the fact that your snippet (intentionally) contains a frank syntax error -- the missing curly bracket -- whereas my snippet (intentionally) contains no syntax errors -- at least, I assume that a comment line followed by a blank line within a Param() block is not a syntax error. In response to your observation that Powershell sometimes (but maybe not always) regards an empty line as the end of a multi-line statement, I should point out that, in my example, it does not seem to be the empty line per se that produces the error; rather, the error occurs precisely when there is a comment line followed by an empty line. For example, the string Both of our snippets have the property that they behave differently, with respect to producing an error, when piped into pwsh stdin compared with other ways of feeding the snippet into PowerShell's parser, but our snippets are opposites with respect to when they produce an error. Here is a demonstration. @(
foreach($namedSnippet in
([Ordered] @{
"Neil's snippet" = "Param(`n#`n`n)"
"Rhubarb's snippet" = @(
"Write-Host 'foo'"
""
"{"
" this is rubbish"
) -join "`n"
}).GetEnumerator()
){
foreach($namedOperation in
([Ordered] @{
"run as a script file" = {$args[0] > foo.ps1 && pwsh -f foo.ps1}
"piped into Invoke-Expression" = {$args[0] | Invoke-Expression }
"piped into pwsh stdin" = {$args[0] | pwsh}
}).GetEnumerator()
) {
[PSCustomObject] @{
"snippet" = $namedSnippet.Name
"operation" = $namedOperation.Name
"produces error?" = [Boolean] (
&{
& $namedOperation.Value $namedSnippet.Value | out-null
} 2>&1
)
}
}
}
) | Format-Table -AutoSize outputs...
|
Beta Was this translation helpful? Give feedback.
-
Consider the following four statements:
statement 1:
"Param(`n#`n)" | Invoke-Expression
statement 2:
"Param(`n#`n`n)" | Invoke-Expression
statement 3:
"Param(`n#`n)" | pwsh
statement 4:
"Param(`n#`n`n)" | pwsh
These four examples cover all combinations of either having or not having an extra linefeed, and piping to either
Invoke-Expression
or topwsh
. In all cases, the string being piped is (I think) valid, albeit boring, PowerShell code.Statements 1, 2, and 3 behave as I would expect, producing no error messages. However, statement 4 produces "ParserError" messages, saying, "Missing ')' in function parameter list" and "Unexpected token ')' in expression or statement"
I have observed this behavior with PowerShell version 7.4.1, but I have no reason to suspect that this version or edition is unique. Windows PowerShell version 5.1 does the same thing.
Main question: Why does the extra linefeed cause errors?
Secondary question: Why does the extra linefeed cause an error in statement 4, but not in statement 2? If the extra linefeed is a syntax error, I would expect
Invoke-Expression
to complain about it. Curiously, PowerShell only ever seems to object to the extra linefeed when piping into PowerShell's stdin. For all other ways of getting PowerShell to execute the string"Param(`n#`n`n)"
(e.g."Param(`n#`n`n)" | Invoke-Expression
,pwsh -c "Param(`n#`n`n)"
,"Param(`n#`n`n)" > a.ps1 && pwsh -f a.ps1
), PowerShell runs the code as expected, without error. Why should PowerShell's parser treat code piped into stdin any differently than it treats code read from any other source?Beta Was this translation helpful? Give feedback.
All reactions