Reputation: 81
I have a script that require 2 arrays as input, and optional logname :
#file:test.ps1
Param(
[string[]]$array1,
[string[]]$array2,
[string]$logName = "log{0}.csv" -f (get-date -format "yyyyMMdd")
)
"array1: {0}" -f ($array1 -join " ")
"array2: {0}({1})" -f ($array2 -join " ") ,$array2.count
"logName: {0}" -f $logName
When run from a PowerShell console, everything is fine:
PS D:\temp> .\test.ps1 -array1 one,two -array2 1,2,3 array1: one two array2: 1 2 3(3) logName: log20190723.csv
But when run by calling powershell.exe
(for scheduled task), only first element from array is grabbed, the rest is passed to the logname parameter.
PS D:\temp> powershell.exe -F D:\temp\test.ps1 -array1 one,two -array2 1,2,3 array1: one array2: 1(1) logName: two
How should I define params to grab all params into the array?
(BTW: I'm using PS4.0, with same result on Windows 2008 and 2012)
Upvotes: 4
Views: 5067
Reputation: 892
From the PowerShell.exe docs:
-File - | <filePath> <args>
[...] Parameters [i.e. the <args>] passed to the script are passed as literal strings, after interpretation by the current shell.
So complex types like arrays cannot be directly provided this way. And be aware that "interpretation by the current shell" and/or command line arguments parsing can do unexpected things to your values: Double quotes may get mangled, arguments are split at non-quoted whitespace, single quotes have no special meaning (always end up in the value as-is), etc. You can use EchoArgs.exe to check what happens.
If you cannot use PowerShell.exe -Command
instead (as suggested by other answers) – e.g. because you are facilitating the Group Policy Logon/Startup/etc. script feature (where gpscript.exe [/logon|/startup|...]
is calling PowerShell.exe
with -File
) – you can work around this limitation by processing the parameter's value inside your script:
$array1 = $array1 -split ','
# You can only have (intended!) whitespace within and between the
# parameter values *if* there are double quotes around them:
# powershell.exe -F test.ps1 -array1 "one, two two"
# And they will remain: $array1 = @("one"," two two")
or
$array1 = Invoke-Expression $array1
# Call like this: powershell.exe -F test.ps1 -array1 "'one',' two two'"
# This way, values can quite safely contain whitespace, and the result will be more clear.
# And you could also pass other complex types like hashtables.
# (Though Invoke-Expression usage is discouraged, but should be ok if you have control over the parameters.)
Upvotes: 0
Reputation: 27606
Use -c instead of -f (command instead of file) (or use neither):
powershell.exe -c D:\temp\test.ps1 -array1 one,two -array2 1,2,3
array1: one two
array2: 1 2 3(3)
logName: log20190723.csv
Upvotes: 5
Reputation: 200493
TL;DR: You cannot pass PowerShell arrays across process boundaries.
The first invocation of your script runs within the current PowerShell process, hence one,two
and 1,2,3
are passed as PowerShell arrays.
The second invocation of your script launches a second PowerShell process as an external program, thus taking a detour leaving and re-entering PowerShell. Because of that one,two
and 1,2,3
are passed to the second PowerShell process as strings, not as arrays, since Windows doesn't know anything about PowerShell arrays.
You could split the parameter values at commas at the beginning of your script to mitigate this limitation:
Param(
[string[]]$array1,
[string[]]$array2,
[string]$logName = "log{0}.csv" -f (Get-Date -Format "yyyyMMdd")
)
if ($array1.Count -eq 1) { $array1 = $array1.Split(',') }
if ($array2.Count -eq 1) { $array2 = $array2.Split(',') }
Note, however, that this might cause problems when you're passing a single argument that contains commas.
Addendum: the behavior you describe for the second invocation should only occur when you have whitespace before or after a comma:
PS C:\> powershell.exe -F C:\path\to\test.ps1 -array1 one, two -array2 1, 2, 3 array1: one array2: 1(1) logName: two
Otherwise the output should be like this:
PS C:\> powershell.exe -F C:\path\to\test.ps1 -array1 one,two -array2 1,2,3 array1: one,two array2: 1,2,3(1) logName: log20190723.csv
Upvotes: 5