It's something unbelievable. This is a PowerShell code snippet in test.ps1
file:
Set-StrictMode -Version 2
mkdir c:\tmp\1 # same with 'md c:\tmp\1'
Start cmd.exe
, navigate to folder with test.ps1
script and run it:
c:\tmp>powershell ".\test.ps1"
This produces the following error:
The variable '$_' cannot be retrieved because it has not been set.
At line:50 char:38
+ $steppablePipeline.Process($_ <<<< )
+ CategoryInfo : InvalidOperation: (_:Token) [], ParentContainsEr
rorRecordException
+ FullyQualifiedErrorId : VariableIsUndefined
Why?
It works when started from PowerShell console but not cmd.exe. I discovered this bug in much larger script. It was a WTF moment.
What is wrong with this simple script?
Even though a workaround has already been found, I thought people might be interested in an explanation.
As to why it behaves differently in the shell versus cmd.exe, see Powershell 2.0 - Running scripts for the command line call vs. from the ISE
As mentioned in the reference, there is a difference between the following two commands:
powershell ".\test.ps1"
powershell -File ".\test.ps1"
When using the first syntax, it seems to mess with scope, causing the Set-StrictMode command to modify the strict mode for functions defined at the global scope.
This triggers a bug (or an incorrect assumption, perhaps) in the definition of the mkdir function.
The function makes use of the GetSteppablePipeline method to proxy the pipeline for the New-Item cmdlet. However, the author neglected to account for the fact that the PROCESS section is still executed even when there is nothing in the pipeline. Thus, when the PROCESS section is reached, the $_ automatic variable is not defined. If strict mode is enabled, an exception will occur.
One way for Microsoft to account for this would be to replace following line:
$steppablePipeline.Process($_)
with the following:
if (test-path Variable:Local:_) {
$steppablePipeline.Process($_)
}
I admit that this may not be the best way to fix it, but the overhead would be negligible. Another option would be to somehow test if the pipeline is empty in the BEGIN section, and then set $_ to $null.
Either way, if you run your scripts with the "powershell.exe -File filename" syntax, then you won't need to worry about it.
It looks like a bug (in PowerShell).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With