I've found out that, if I pass only a dash to an argument of PowerShell 5.1 script on Windows 10, like this:
powershell.exe -File Test.ps1 -
I get a strange error message saying:
C:\path\Test.ps1 : Cannot process argument because the value of argument "name" is not valid. Change the value o f the "name" argument and run the operation again.
- CategoryInfo : InvalidArgument: (:) [Test.ps1], PSArgumentException
- FullyQualifiedErrorId : Argument,Test.ps1
The Test.ps1
is only:
echo "foo"
The actual problem I face though is that, when the script declares any mandatory parameter:
param (
[Parameter(Mandatory)]
$value
)
echo "foo"
Then executing the script the same way (with -
argument) does nothing at all. No output. No error message. It just hangs for a few seconds. And then a control returns to a command prompt.
C:\path>powershell.exe -File Test.ps1 -
C:\path>_
What does the -
mean to PowerShell (5.1)?
On the contrary, with PowerShell 2.0 on Windows 7, I get script usage in this case:
C:\path>powershell.exe -File Test.ps1 -
Test.ps1 [-value] <Object> [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
C:\path>_
What makes sense (a missing mandatory parameter).
And without the mandatory parameter declaration, the script works (prints it output):
C:\path>powershell.exe -File Test.ps1 -
foo
C:\path>_
The behavior should be considered a bug - something that starts with -
but isn't a valid parameter name should be passed as a positional argument rather than reporting an error.
The bug affects:
Windows PowerShell (as of v5.1.18362.145) - it is unclear if a fix will ever be made.
... the value of argument "name" is not valid ...
) or (b) the -
is quietly ignored depends on whether your parameter has a parameter attribute such as [Parameter(Mandatory)]
[1] and/or your param()
block has a [CmdletBinding()]
attribute (if so, (b) applies).PowerShell Core 6.x - that is, the problem will be fixed in v7 (current as of this writing: v7.0.0-preview.3); I don't know if 6.2.2, the stable version current as of this writing, will be fixed - we'll see what happens to the bug report on GitHub you've filed.
As for a workaround (works analogously in PowerShell Core):
Use -Command
instead of -File
.
While that changes the semantics of how the command line is parsed[2], in simple cases such as this one the difference won't matter:
C:\> powershell -Command ./Test.ps1 - # note the "./"
Note the ./
, because using -Command
(-c
) makes PowerShell parse the arguments as if they were PowerShell code, and the usual restrictions re executing scripts by filename only apply (to prevent accidental execution of a file in the current directory, you need a path component to explicitly signal that intent, hence prefix ./
or .\
is needed).
If your script file path needed quoting, you'd have to use quoting and prepend &
, the call operator; e.g.:
C:\> powershell -Command "& \"./Test.ps1\" -"
[1] Adding a [Parameter()]
attribute to a declared parameter implicitly makes the enclosing script/function an advanced one, in which case different parsing rules apply. The [CmdletBinding[]
attribute, which is applied to a param(...)
block as a whole, explicitly marks a script / function as an advanced one.
[2] See this answer for the differences between how -File
and -Command
arguments are parsed.
This isn't an answer but I'm curious as well. If you've already figured it out I'd be interested in what you found. Otherwise, in case it helps, Powershell -h
says everything after -file
is the script and any arguments passed to it.
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
functions and variables that the script creates are available in the
current session. Enter the script file path and any parameters.
File must be the last parameter in the command, because all characters
typed after the File parameter name are interpreted
as the script file path followed by the script parameters.
Tokenizer reads it in as a CommandArgument.
Powershell >> $Errors = $Null
Powershell >> [System.Management.Automation.PSParser]::Tokenize("powershell -file test.ps1 -", [ref]$Errors)[3]
Content : -
Type : CommandArgument
Start : 26
Length : 1
StartLine : 1
StartColumn : 27
EndLine : 1
EndColumn : 28
So it seems like the issue is further up the chain but I couldn't find a simple way to call the Parser functions to test.
I do see that there's a case that shouldn't occur where the error is swallowed and null returned which might cause it to just stop like it does in your example
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