1

I'm trying to pass a string array to powershell through vbscript. I got the params in the file.ps1 script:

param (
    [string[]]$target
)

I'm trying to call file.ps1 through vbscript.

I want $target = @('c:\dev','d:\lib') to be passed in.

I currently have in my vbscript :-

target1 = """c:\dev"", ""d:\lib"""
Set objShell = CreateObject("Wscript.Shell") 
objShell.run("powershell.exe -noexit -ExecutionPolicy Unrestricted -file .\file.ps1 -target1 """ & target & """")

which returns: c:\dev, d:\lib and which isn't the powershell string array format "c:\dev", "d:\lib"

Update - Thanks mklement0 and alex-dl for your answers!

Mango99
  • 13
  • 3
  • 1
    Remove the `""` on each side - otherwise you're passing the literal string value `"c:\dev, d:\lib"` – Mathias R. Jessen Feb 05 '21 at 12:37
  • removing "" would cause a syntax error. In vbscript " is used as the escape character. so if i was to print `"""c:\dev"", ""d:\lib"""` into vb console it would return `"c:\dev", "d:\lib"` – Mango99 Feb 05 '21 at 12:43
  • No it would not, `"... -target " & target & ""` is a perfectly valid expression – Mathias R. Jessen Feb 05 '21 at 15:03
  • @Mathias, true, though the `& ""` is then unnecessary. The fundamental problem here, however, is the use of the `-File` CLI parameter, which fundamentally doesn't support passing _arrays_; `-Command` (`-c`) must be used. – mklement0 Feb 05 '21 at 17:05

2 Answers2

2

alex-dl's helpful answer contains an effective solution, as long as the array's elements don't need quoting, but let me try to break it down conceptually in more detail:

  • The -File parameter of PowerShell's CLI, powershell.exe (pwsh in PowerShell (Core) 7+) fundamentally does not support passing arrays to PowerShell code, because all arguments are interpreted strictly as whitespace-separated, with verbatim content.

    • E.g., "c:\dev", "d:\lib" on the command line is parsed as two arguments:
      • c:\dev, (note the trailing ,, syntactic " quotes stripped)
      • d:\lib
  • You must use the -Command (-c) option in order to pass arrays.

    • -Command fundamentally changes how the arguments are parsed:
      • All arguments are stripped of syntactic (non \"-escaped) " quotes.
      • The resulting tokens are space-concatenated to form a single string.
      • The resulting string is then interpreted as PowerShell code, i.e. as if you had submitted it from inside a PowerShell session.
    • This therefore enables all of PowerShell's features, such as passing arrays with ,, '...' (single-quoting), ..., and notably also means that references to PowerShell variables (e.g. $HOME) are recognized (unlike with -File).

See this answer for more guidance on when to use -File vs. -Command (-c).

Therefore, the best approach in your case is:

target = "'c:\dev', 'd:\lib'" ' Note the embedded '...'-quoting
Set objShell = CreateObject("Wscript.Shell") 
' Note the use of -c (-command) instead of -file
objShell.Run("powershell.exe -noexit -ExecutionPolicy Unrestricted -c .\file.ps1 -target " & target)

Using embedded '...'-quoting simplifies passing the array elements in a way that PowerShell sees them as individually quoted (with the values at hand, this isn't strictly necessary, but it may be in other cases).

Doing this with embedded "..."-quoting gets unwieldy, because each embedded " must then be escaped as \"" (sic):

  • "" to escape the " inside the VBScript string,
  • and \ to ensure that \" is ultimately passed on the command line, which PowerShell requires for escaping " on the command line[1] (whereas PowerShell-internally, it is `" or (alternatively, inside a double-quoted string) "").
target = "\""c:\dev\"", \""d:\lib\"""
Set objShell = CreateObject("Wscript.Shell") 
objShell.Run("powershell.exe -noexit -ExecutionPolicy Unrestricted -c .\file.ps1 -target " & target)

[1] While in Windows PowerShell you can situationally get away with "" instead of \", it can break, especially if the overall -c argument is enclosed in "...". This problem has been fixed in PowerShell (Core) 7+, where you can now use "" and \" interchangeably.
E.g., when invoked from cmd.exe,
powershell -c " ""ab c"".length " breaks, whereas
pwsh -c " ""ab c"".length " works.

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

You could use the following vbscript:

target1 = """c:\dev, d:\lib"""
Set objShell = CreateObject("Wscript.Shell") 
objShell.run("powershell.exe -Command .\file.ps1 -target " & target1)

And this powershell script:

param (
    [string[]]$target
)
foreach ($t in $target) {
    write-output $t
}
Read-Host -Prompt "Press Enter to exit"

Without -Command the argument is always interpreted as a single string.

alex-dl
  • 802
  • 1
  • 5
  • 12
  • Good point about the need for `-Command` if _arrays_ are to be passed. Note that the escaped embedded double quotes (`""` inside `"""c:\dev, d:\lib"""`) ultimately have no effect here and PowerShell ultimately sees the array elements as unquoted (which works fine in this case); additional work is needed if the array elements need quoting individually (which Mango99 (ineffectively) attempted), such as for elements containing spaces. – mklement0 Feb 05 '21 at 16:25