3

I'm having some trouble with Powershell, I have code that looks like this:

param
(
    [Parameter(Mandatory=$true)]
    $Array = ''
)

foreach ($member in $Array){
    Write-Host "TEST"

    $server = $member["server"]
    $path = $member["path"]
    $key = $member["key"]

    Write-Host $server
    Write-Host $path
    Write-Host $key
}

When I provide the following line as input, the script only prints "TEST" and nothing further, but when I define $Array within the script itself with the exact same code, the script works as expected.

@(@{"server" = "server1"; "path" = "\\path1"; "key" = "key1"}, @{"server" = "server2"; "path" = "\\path2"; "key" = "key2"}, @{"server" = "server3"; "path" = "\\path3"; "key" = "key3"})

The expected output is:

TEST
server1
\\path1
key1
TEST
server2
\\path2
key2
TEST
server3
\\path3
key3

This is my first reach into PowerShell coming from a Python background.

It seems that if this array is passed at the command line level, it works. However, if the script prompts for the input and it's entered at that point, it fails. Where am I going wrong?

To clarify, the below code works perfectly well, with each key's value being printed to the console.

$Array = @(@{"server" = "server1"; "path" = "\\path1"; "key" = "key1"}, @{"server" = "server2"; "path" = "\\path2"; "key" = "key2"}, @{"server" = "server3"; "path" = "\\path3"; "key" = "key3"})

foreach ($member in $Array){
    Write-Host "TEST"

    $server = $member["server"]
    $path = $member["path"]
    $key = $member["key"]

    Write-Host $server
    Write-Host $path
    Write-Host $key
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AidenWebb
  • 589
  • 2
  • 7
  • 14
  • 2
    Unable to reproduce. Which version of PowerShell are you using? Inspect `$PSVersionTable['PSVersion']` if in doubt – Mathias R. Jessen Oct 28 '16 at 12:07
  • I'm using Powershell 4.0 – AidenWebb Oct 28 '16 at 12:08
  • @Awebb Can you show us the exact command line you use to invoke the script? how you pass the argument – Mathias R. Jessen Oct 28 '16 at 12:09
  • I'm running this in ISE with F5. It then prompts for the parameter. I then copy and paste everything after the "$Array = " into the prompt. – AidenWebb Oct 28 '16 at 12:26
  • Just save it to file,, open Powershell and do something like `.\1.ps1 @(@{"server" = "server1"; "path" = "\\path1"; "key" = "key1"}, @{"server" = "server2"; "path" = "\\path2"; "key" = "key2"}, @{"server" = "server3"; "path" = "\\path3"; "key" = "key3"})` – Andrey Marchuk Oct 28 '16 at 12:31
  • Andrey, it's odd that that works, but doesn't work in ISE. Is there any way I can make this work in ISE? – AidenWebb Oct 28 '16 at 12:34
  • Actually, it seems that if this array is passed at commandline level, it works. However if the script prompts for the input and it's entered at that point, it fails. – AidenWebb Oct 28 '16 at 12:37
  • possible duplicate http://stackoverflow.com/questions/15120597/passing-multiple-values-to-a-single-powershell-script-parameter – Esperento57 Oct 28 '16 at 12:39

2 Answers2

4

I think this boils down to when you are being prompted for the input (by not specifying the value for the parameter on the command line) it is being read in a similar manner to using the Read-Host cmdlet. The output of that cmdlet is either a [System.String] or [System.Security.SecureString].

As such, instead of the input to the script/function being a proper object, it is just a long string. You can see the difference if you add a debug line to your script just after the param() block:

Write-Debug ($Array | Out-String)

You will need to set $DebugPreference="Continue" on the console, before you run the script, to view debug output. When you run the script, you should see the difference it makes using the prompted input.

Personally I wouldn't try much harder to collect "complex" data from the console prompt and look at ways to make sure you feed in the data on the command line, as you have already tried.

Charlie Joynt
  • 4,411
  • 1
  • 24
  • 46
0

You need to pass a parameter like this:

.\1.ps1 @(@{"server" = "server1"; "path" = "\\path1"; "key" = "key1"}, @{"server" = "server2"; "path" = "\\path2"; "key" = "key2"}, @{"server" = "server3"; "path" = "\\path3"; "key" = "key3"})

When you use ISE, the parameter is handled as a string, because you actually pass a string and PowerShell syntax is not applied to it. You can verify it by adding $Array.GetType().Name to your script.

It somewhat helps if you will define your variable properly:

[System.Collections.Generic.Dictionary``2[System.String,System.String][]] Array

But UI is really designed to pass strings or string arrays and not more complex structures.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Andrey Marchuk
  • 13,301
  • 2
  • 36
  • 52