121

I have a script to which I pass server name(s) in $args.

This way I can do stuff to this (these) server(s) using foreach:

.\script.ps1 host1 host2 host3

foreach ($i in $args)
{
    Do-Stuff $i
}

I'd like to add a named optional parameter called vlan. I've tried:

Param(
    [string]$vlan
)

foreach ($i in $args)
{
    Write-Host $i
}
Write-Host $vlan

It works if you pass a -vlan parameter but if you don't then the script auto assigns the last server name to $vlan.

So, how can you pass single or multiple parameters plus an optional named parameter to a PowerShell script?

Ideally, here are valid examples:

.\script.ps1 host1
.\script.ps1 host1 host2 host3
.\script.ps1 host1 host2 -vlan office
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jcarpio
  • 3,350
  • 5
  • 23
  • 22

5 Answers5

225

The easiest way is probably to use two parameters: One for hosts (can be an array), and one for vlan.

param([String[]] $Hosts, [String] $VLAN)

Instead of

foreach ($i in $args)

you can use

foreach ($hostName in $Hosts)

If there is only one host, the foreach loop will iterate only once. To pass multiple hosts to the script, pass it as an array:

myScript.ps1 -Hosts host1,host2,host3 -VLAN 2

...or something similar.

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Bill_Stewart
  • 22,916
  • 4
  • 51
  • 62
  • 13
    thanks for including the info on how to call the script - I'm often missing little pieces like that in powershell. – Jan Bühler Feb 21 '18 at 16:00
  • 2
    If you are executing outside a powershell (in wsl for example), then you need to use the `-Command` flag and to quote the variable. `pwsh -Command myScript.ps1 -Hosts "host1,host2,host3" -VLAN 2` – miah Jun 01 '22 at 19:27
  • @miah Nice one. I'd adjust your command a little bit like `pwsh -Command .\myScript.ps1 -Hosts "host1,host2,host3" -VLAN 2` – Mojtaba Nov 17 '22 at 13:41
32

One way to do it would be like this:

 param(
       [Parameter(Position=0)][String]$Vlan,
       [Parameter(ValueFromRemainingArguments=$true)][String[]]$Hosts
    ) ...

This would allow multiple hosts to be entered with spaces.

DeanOC
  • 7,142
  • 6
  • 42
  • 56
Nitz
  • 337
  • 3
  • 2
28

Parameters take input before arguments. What you should do instead is add a parameter that accepts an array, and make it the first position parameter. ex:

param(
    [Parameter(Position = 0)]
    [string[]]$Hosts,
    [string]$VLAN
    )

foreach ($i in $Hosts)  
{ 
    Do-Stuff $i
}

Then call it like:

.\script.ps1 host1, host2, host3 -VLAN 2

Notice the comma between the values. This collects them in an array

Frode F.
  • 52,376
  • 9
  • 98
  • 114
1

I was having issues doing this in my yml file and then I found this link and adding "-Command" to the front of my script solved it:

https://michlstechblog.info/blog/powershell-passing-an-array-to-a-script-at-command-line/

Paul Fabbroni
  • 123
  • 3
  • 13
-7

I call a scheduled script who must connect to a list of Server this way:

Powershell.exe -File "YourScriptPath" "Par1,Par2,Par3"

Then inside the script:

param($list_of_servers)
...
Connect-Viserver $list_of_servers.split(",")

The split operator returns an array of string

BR1COP
  • 321
  • 2
  • 5
  • This is a horrible way to do it. You should be making $list_of_servers an array: `[string[]]$list_of_servers` – az1d Aug 31 '21 at 07:27
  • Thank you, never realized it was so scary. That works from many years. – BR1COP Sep 01 '21 at 09:11