0

I have two PowerShell scripts and use them on Linux with PowerShell Core, and want to pass the switch parameter from one.ps1 to second.ps1, but the $args is populated as a string with True and False sub-strings in it, which is not accepted by the second.ps1, as it has validation in param block.

How do I change to make it work? I know I can manually enumerate all the parameters of second.ps1 and make up a command argument string, but considering there are so many parameters in second.ps1, is there a better way ?

My scripts look like this:

# one.ps1
param(
    [string][ValidateSet("value1", "value2")]$para1,
    [switch]$para3 = $false
)

Write-Host "one.ps1: para1=$para1"
Write-Host "one.ps1: para3=$para3"

Write-Host "args=$args"

pwsh ./second.ps1 $args

second.ps1

# second.ps1
param(
    [string][ValidateSet("value1", "value2")]$para1="value1",
    [string][ValidateSet("value3", "value4")]$para2="value3",
    [switch]$para3 = $false,
    [switch]$para4 = $false,
    [switch]$para5 = $false,
    [switch]$para6 = $false,
    [switch]$para7 = $false,
    [switch]$para8 = $false
)

Write-Host "second.ps1: para1=$para1"
Write-Host "second.ps1: para2=$para2"
Write-Host "second.ps1: para3=$para3"
Write-Host "second.ps1: para4=$para4"
Write-Host "second.ps1: para5=$para5"
Write-Host "second.ps1: para6=$para6"
Write-Host "second.ps1: para7=$para7"
Write-Host "second.ps1: para8=$para8"

Here is the command to use them

pwsh one.ps1 -para1 value1 -para2 value3 -para3:true -para4:false

Error message:

one.ps1: para1=value1
one.ps1: para3=True
args=-para2 value3 -para4 False
second.ps1: Cannot validate argument on parameter 'para1'. The argument "False" does not belong to the set "value1,value2" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.
absfdlf
  • 1
  • 1
  • [1] take a look at `$PSBoundParameters`. ///// [2] switches default to `$False`, so there is no need to set them in your parameter block. also, there is no need to use `-SwitchParam:$True` ... since merely calling `-SwitchParam` sets it to `$True`. – Lee_Dailey Jun 09 '21 at 06:15
  • @iRon well, no really, if I use `.IsPresent`, how can I tell whether the arg in `$args` is a `switch` and apply IsPresent? – absfdlf Jun 09 '21 at 07:54
  • @Lee_Dailey [1] `$PSBoundParameters` only stores the parameters defined in param block, other parameters that are passed through command line are omitted, here is the content of `[para1, value1] [para3, True]` in `one.ps1` and since we never reach to `second.ps1`, can't tell the content of it. [2] removing `=$false` doesn't help on resolving the original issue... – absfdlf Jun 09 '21 at 07:58
  • the Question is about passing a switch parameter ... that seems to require the item to be defined in the parameter block. [*grin*] – Lee_Dailey Jun 09 '21 at 08:28
  • `pwsh ./second.ps1 $args` --> `pwsh ./second.ps1 -para1:$para1 -para3:$para3` ? – iRon Jun 09 '21 at 08:31
  • Does this answer your question? [How to pass a switch parameter to another PowerShell script?](https://stackoverflow.com/questions/38009106/how-to-pass-a-switch-parameter-to-another-powershell-script) – Legolas Jan 24 '22 at 13:12

2 Answers2

0

I am sorry but I think passing $args as named parameter for the second script won't be that easy. $args is an array of the arguments. Each argument separated by a whitespace. When you pass $args to the second script it will be counted as one argument at position one. $para1 of the second script will take the whole array as its positional parameter.

function one 
{# one.ps1
    param(
        [string][ValidateSet("value1", "value2")]$para1,
        [switch]$para3 = $false
    )

    Write-Host "one.ps1: para1=$para1"
    Write-Host "one.ps1: para3=$para3"

    Write-Host "args=$args"
    Write-Host "argsType=$($args.GetType().BaseType)"

    $args
}

$arg = one -para1 value1 -para2 value3 -para3:$true -para4:$false

Result:

one.ps1: para1=value1
one.ps1: para3=True
args=-para2 value3 -para4: False
argsType=array

PS D:\test> $arg
-para2
value3
-para4:
False

As you can see -para2 value3 isn't a single string but two strings as part of an array. You could write code to rebuild the named prameter string but I think that will be way more work than just to enumerate them. Another soluten would be to use splatting. However you wold have to provide a hashtable instead of just a string for the first script. Here is a way to call another function with args via splatting.

T-Me
  • 1,814
  • 1
  • 9
  • 22
0

Splat the $PSBoundParameters to pass the arguments bound to declared parameters in one.ps1, splat $args to pass the remaining arguments:

# one.ps1
param(
    [string][ValidateSet("value1", "value2")]$para1,
    [switch]$para3 = $false
)

Write-Host "one.ps1: para1=$para1"
Write-Host "one.ps1: para3=$para3"

Write-Host "args=$args"

pwsh ./second.ps1 @PSBoundParameters @args
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • Thanks, the splatting pushes a step further, but it has another issue, all the switch names are accepted by `second.ps1` but the values of them are ignore, thus no matter the value is `True` or `False`, since switch name is present, it will be treated as `True`, Note the `para4=True` in the output: ```second.ps1: para1=value1 second.ps1: para2=value3 second.ps1: para3=True second.ps1: para4=True second.ps1: para5=False second.ps1: para6=False second.ps1: para7=False second.ps1: para8=False``` – absfdlf Jun 09 '21 at 11:39