
These also produce the same error:
$services = Get-Service
foreach($service in $services){$service.Name} &
for($i=1; $i -lt 10; $i++){$i} &
$i = 1
do{$i; $i++} While($i -lt 10) &
I'm guessing anything that doesn't produce a pipeline will result in this kind of error.
@BrucePay Could you please comment the Issue?
I was going to suggest a workaround, but you'll get a confusing error.
In general, you can turn a statement into a pipeline by putting it in a script block, e.g.
& { while ($true) { ... } }
Unfortunately, the transformation to use Start-Job makes an invalid change to your script by adding $using to an expression that does not support $using.
& { while($x -lt 10000) { sleep 100; $x+=1 } } &
That's a delicious and-sandwich.
Just an FYI - This is happening also in Windows PowerShell. I had to check just in case it was just a PowerShell Core issue.
Ah! Two different error as in Windows states "The ampersand (&) character is not allowed. The & operator is reserved for future use...".
:)
@MaximoTrinidad "&" is not implemented in Windows PowerShell to start a background job. You cannot test it in PS 5.1.
@markekraus Yeah, but the job doesn't complete
@dfinke while($x -lt 10000) { sleep 100; $x+=1 } would take 11 days to run. That's 1,000,000 seconds minium.
We should get clarity on what the real issue is:
(I haven't looked at the source code, so do tell me if I got things wrong.)
Post-positional & not being supported with a "naked" expression-based statement _involving flow-control keywords_ is consistent with not being able to use such statements in a _pipeline_:
do { 1 } while ($false) & # FAILS: "Missing expression after '&' in pipeline element."
do { 1 } while ($false) | Measure-Object # FAILS: "An empty pipe element is not allowed."
(By contrast, a simple expression without flow-control keywords works fine in both cases).
It looks like such statements aren't supported by the _parser_:
The error messages stem from the parser considering do { 1 } while ($false) a _complete statement in its own right_ and parsing the & / | Measure-Object as a _new_ statement, which obviously fails; in short: you'll get the same error message if you execute & and | Measure-Object in isolation.
If the intent is to support such statements, the parser needs to be fixed (and the confusing errors would go away).
If the intent is NOT to support such statements - and require explicit conversion to a _command_ first - the confusing error messages are problematic.
There is an additional, unrelated problem:
When you convert such a statement to a _command_ with & { ... }, . { ... }, $(...) or @(...) - as a prerequisite for combining it with & or | - you _may_ run into the $using: problem @lzybkr has discovered when using &.
Seemingly, the problem surfaces only if a namesake variable of a variable used as a _loop variable_ in the script block exists in the _calling_ scope, execution fails:
$v = 0 # define $v in calling scope
$jb = & { foreach($v in 1..2) { $v } } & # use $v as loop variable in script block
Receive-Job $jb -Wait -AutoRemove
The above yields:
Cannot find drive. A drive with the name 'using' does not exist.
+ CategoryInfo : ObjectNotFound: (using:String) [], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound
+ PSComputerName : localhost
$(...) or @(...) (to run the enclosed command to completion first) rather than & { ... } results in the same behavior, as does . { ... }.$v is not defined in the calling scope, the problem doesn't occur.The behaviour for & is going to be weird because it has different meanings at the beginning (call operator) and end (backgrounding) of a statement. In the case of
while (1) { $true } &
you get an error because the closing brace ends that statement. The next token read (the '&') is the first token of the next statement i.e. the call operator. There is nothing after it so you get the correct error. You get the same error with
write-output hi; &
since ';' terminates the current statement and & is the beginning of the next statement. If you do provide an argument to '&', it works properly:
PS[1] (117) > while ($false) { "Hi" } & write-output Hi
Hi
In other words, everything is working properly and returning the "right" error message in the case of an error. Now if attempting to background a flow-control statement is a very common, we can probably hack the parser to provide a more specific error e.g. "you can't background flow-control statements; try using & { ... } &" or something.
(Historical note: we used & as the call operator because that's what Perl used. Very early in the project, we aligned the syntax with Perl since that was, at the time, the dominant sysadmin language. After not too long, we switched the base syntax to align with C# but retained some of the Perl-isms: trap from a Perl 6 proposal, using the @ symbol for hashes, $_ and & as the call operator. In retrospect, we probably should have used a different symbol (e.g. ^) instead since we always intended to implement backgrounding.)
The using: error is a result of the runtime trying to be smart and adding $using: to variables in the statement to be backgrounded for which there is a current in-scope variable. I'll have to look at the code to see why it's failing. I think this should be tracked as a seperate issue if it isn't already.