2

Consider the following function:

function f1{
    param(
        $sb = {},
        $s  = ''
    )
    if ($sb -isnot [scriptblock]) { 'scriptblock' }
    if ($s  -isnot [string]     ) { 'string' }
}

Now invoke it with a splat parameter:

PS C:\> $splat = @{foo='bar'}
PS C:\> f1 @splat

As expected, nothing is returned. Now try it again with a $null splat parameter:

PS C:\> $splat = $null
PS C:\> f1 @splat
scriptblock

Oddly, scriptblock is returned. Clearly, at least for the [scriptblock] parameter, powershell is not honoring the default value when a $null splat parameter is used. But powershell does honor the default value for the [string]. What is going on here?

For what types does Powershell honour default values when using $null splat parameters?

alx9r
  • 3,675
  • 4
  • 26
  • 55
  • 3
    I don't think its the type, its the order of the parameters. When you try to splat a null powershell is just passing it as the first parameter. Then the second parameter gets its default value. – Mike Zboray Mar 16 '15 at 22:46
  • 1
    It looks like you're correct. Switching the parameters yields `string` instead. – alx9r Mar 16 '15 at 22:52

4 Answers4

2

Isn't this just normal application of positional parameters? You are splatting a single $null which is being applied to $sb.

Compare:

> function f{ param($sb = {}, $s = '') $PSBoundParameters }
> $splat = @(1,2)
> f @splat
Key                                                 Value
---                                                 -----
sb                                                      1
s                                                       2
> f @flkejlkfja
Key                                                 Value
---                                                 -----
sb
> function f{ param($aaa = 5, $sb = {}, $s = '') $PSBoundParameters }
> f @splat
Key                                                 Value
---                                                 -----
aaa                                                 1
sb                                                  2
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
2

It's an old question but if it is still interesting...

As others have written with $splat = $null calling f1 @splat the first parameters will get the value $null instead it's default value.

If you want the parameters use their default value in this case you have to use $splat = @{} or $splat = @().

alx9r
  • 3,675
  • 4
  • 26
  • 55
VargaJoe
  • 175
  • 5
  • 10
1

Here's a demonstration to help understand what's happening

$splat = @{foo='bar'}
"$(&{$args}@splat)"
-foo: bar

When you splat the hash table, it gets converted to -Key: Value string pairs that become the parameters to your function.

Now try:

$splat = $null
"$(&{$args}@splat)"

Nothing is returned. There are no keys to generate the parameter string from, so the end result is the same as not passing any parameters at all.

mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • Thanks! This makes what's happening much more clear. – alx9r Mar 17 '15 at 15:50
  • A value _is_ being passed when you splat `$null`: `$splat = $null; & { $Args.count } @splat` yields `1`. The value being passed is `$null`, which makes no effective difference with `$Args`, but does matter with declared parameters, as in the OP's case. – mklement0 May 05 '18 at 02:03
1

To complement Etan Reisner's helpful answer with a more direct demonstration that splatting $null indeed passes $null as the first (and only) positional argument:

$splat = $null
& { [CmdletBinding(PositionalBinding=$False)] param($dummy) } @splat

The above yields the following error:

A positional parameter cannot be found that accepts argument '$null'.
...

Decorating the param() block with [CmdletBinding(PositionalBinding=$False)] ensures that only named parameter values can be passed, causing the positional passing of $null from splatting to trigger the error above.

Note that using the special "null collection" value ([System.Management.Automation.Internal.AutomationNull]::Value) that you get from commands that produce no output for splatting is effectively the same as splatting $null, because that "null collection" value is converted to $null during parameter binding.


VargaJoe's helpful answer explains how to construct a variable for splatting so that no arguments are passed, so that the callee's default parameter values are honored.

mklement0
  • 382,024
  • 64
  • 607
  • 775