Please feel free to provide feedback or file bugs here.

Allow splatting without an intermediate variable.

instead of
$splat = @{name = "value"}
verb-noun @splat

Allow verb-noun @{name = "value"}

This would make for a much cleaner and more natural look to parameters. Letting them be in the usual place of after and below the function.

There is a stackoverflow question relating to this, that should explain it more - http://stackoverflow.com/questions/35188172/why-do-i-need-to-splat-to-a-variable-first

47 votes
Sign in
Check!
(thinking…)
Reset
or sign in with
  • facebook
  • google
    Password icon
    I agree to the terms of service
    Signed in as (Sign out)

    We’ll send you updates on this idea

    Michael BMichael B shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

    Thank you for your input. Based on its current ranking compared to other feedback items and product schedule, work on this item is pending (and will be driven by) further customer input. If you did not open this issue and are also impacted by it, please vote this item up.

    15 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      I agree to the terms of service
      Signed in as (Sign out)
      Submitting...
      • David ZemdegsDavid Zemdegs commented  ·   ·  Flag as inappropriate

        When the cmdlet parameter parser encoutners a '@' it assumes that what follows is a variable name that is a hash table. It seems that to detect a '{' following a '@' and use the standard hashtable parsing would be reasonably simple?

      • Alan MervitzAlan Mervitz commented  ·   ·  Flag as inappropriate

        I have published a PowerShell module with two commands to address this need, this could be used as inspiration for a built-in language feature or used until then. It supports nested objects and hashtables. Here's an example of a very simple example that splats an inline hashtable directly with Write-Host:

        > Invoke-Splat Write-Host @{Object = "Hello"; BackgroundColor = "Green" }

        See https://github.com/amervitz/amps for source code and examples, and install the module from https://www.powershellgallery.com/packages/amps/.

      • Dan SedlacekDan Sedlacek commented  ·   ·  Flag as inappropriate

        +1 I am definitely for something like this in the language. The necessity of creating an intermediate variable just seems redundant and I am not a fan of the jankiness of using backticks. I would be in favor of cmdlets not requiring the backtick if we could lay down arguments that way, but I imagine that would cause way more problems than it would be worth :)
        The main motivation for my case is that we check-in our powershell scripts to source control (like any good sysadmin should these days :D) and splatting helps greatly to keep the line length underneath the metric of what is allowed for a maximum line length. Our source control team has it set to 80 characters so we have to fight super hard to keep scripts under that length. I also think that maintenance of scripts where we need to change a variable within the splat's hashtable is much more simple than backticks because, as others mentioned, it is less error prone.

        One way around it i've thought about is to splat through the pipe:
        @{InputObject = 'hi' } | % { Write-Output @_ }

        I'm not a particular fan of this since you have to iterate over one element with ForEach-Object to resolve the splat parameter being passed through the pipe, along with other flaws I'm sure others will be happy to point out ;)
        I am not arguing for a particular syntax, but I would LOOOOOVE to have this feature added into the language!

      • Eric ScipleEric Sciple commented  ·   ·  Flag as inappropriate

        +1. I tend to avoid storing to an intermediate variable just to enable splatting. I find it makes the readability worse.

        This syntax seems most intuitive to me: @@{ key1 = val1 ; key2 = val2 }

        To step back a minute, the reason why I want to do this in the first place is simply to avoid using the infamous backtick. So maybe there is some other fancy language addition that could solve the same problem.

      • Derp McDerpDerp McDerp commented  ·   ·  Flag as inappropriate

        After thinking about it more, the following solution has less irregularity to the grammar:

        .{} should be a key splatting postfix operator
        .[] should be an index splatting postfix operator

        And @ shouldn't appear.

        So the examples would now be:

        $someExpr.{A;B} # multiple keys
        $someExpr.{} # empty body means all keys
        $someExpr.{
        A
        B = 2 # replacement value if missing
        $true = $false # replacement value if missing
        ($a = $false) # assign $a to $false then return $a
        "some$True"
        }
        # splat a hash literal:
        foo @{
        name = "value"
        }.{}

        $someExpr.[0..3;5;6]
        $someExpr.[$foo,$bar]
        $someExpr.[$foo;$bar]
        $someExpr.[
        1 = 3 # replacement value if missing
        $a = 3 # replacement value if missing
        ($b = 3) # assign $b to 3 then return $b
        ]
        $someExpr.[] # empty body means all keys

      • Derp McDerpDerp McDerp commented  ·   ·  Flag as inappropriate

        Here is what a proper splatting proposal needs to do:

        1. it should work on an expression instead of a variable, e.g. @{$foo.Bar()}
        2. it should let you specify a subset of keys/indices to splat (optional, nice to have: the keys shouldn't need to be quoted), e.g. @{PSBoundParameters{A,B}}
        3. (optional, nice to have) it should let you splat inside a hashtable literal, e.g. @{ a = 1 ; @{$foo} }
        4. (optional, nice to have) if keys/indicies aren't found it should let you specify a (lazily evaluated) replacement value

        None of the suggestions here come close to do that. They all just do the trivial thing of splatting a hash table literal.

        One thing that could solve all the above (except splatting a subset of arrays) is that PowerShell currently treats this syntax:

        $foo.{bar}

        as:

        $foo.({bar})

        and applies .ToString() to {bar} resulting in "bar".

        A future PowerShell could break backwards compatibility with that and treat is as a way to splat a subset, e.g.

        @someExpr.{A,B}

        @someExpr.{} # if no keys, it should be treated as if you specified all keys

        @someExpr.{
        a = 2 # replacement value if missing
        }

        # if the identifier is missing, treat it as a splatted hashtable literal
        foo @.{
        name = "value"
        }

      • PetSerAlPetSerAl commented  ·   ·  Flag as inappropriate

        @Frode F.

        >Then why shouldn't this work?

        1..3|Select-Object @(@{Name='Value';Expression={$_}})

        Should it be splatting or should it retain its original meaning?

      • Frode F.Frode F. commented  ·   ·  Flag as inappropriate

        @Per Martin: Backticks are evil and should only be allowed inside of quotes. He isn't suggesting that they replace the splatting as it is, but simply extend it. Then we could finally be able to write parameters using multiple lines without the fear of breaking your script because a simple whitespace came behind the awful backtick. :-)

        When this works:

        $t = @{
        Name = "Value1"
        Age = 99
        }

        Get-Person @t

        Then why shouldn't this work?

        Get-Person @(@{
        Name = "Value1"
        Age = 99
        })

        Maybe @t should have been @$t in the first place, but let's not change that.

      • Per Martin MøllerPer Martin Møller commented  ·   ·  Flag as inappropriate

        What would be the point of this? It totally defeats the point of using splatting.

        Splatting is smart for when you use the same parameters for different cmdlets or calling the same cmdlet multiple times with only a few parameters changing, or for building up parameters.

        If you do it like in this idea then you cannot reuse the splat since it not stored in a variable.

        If it is purely for your code formatting then use the backtick to make it look "pretty" like this:
        New-ResourceGroup `
        -ResourceGroupName = $ResourceGroupName `
        -Location = $location `
        -Whatif = $true `
        -ErrorVarible = "err" `
        -ErrorAction = "SilentlyContinue"

      • Roman KuzminRoman Kuzmin commented  ·   ·  Flag as inappropriate

        There are two issues, in my opinion.

        The second issue: there should be a way to invoke splatting without an intermediate variable. Operators are expected to be applied to expressions. So if this operator is <splat> (I am not proposing any syntax yet) then we should be able to do

        command <splat> <expression>

        e.g.

        get-it <splat> $parameters # still in a variable but it is used as an expression
        get-it <splat> (get-param) # some command gets parameters
        etc.

        The first issue: command line continuation with backticks should be improved (namely, to allow white spaces and comments after it) or yet another clear syntax should be introduced. We are talking about splatting as a work around exactly this issue, after all.

      • MattMatt commented  ·   ·  Flag as inappropriate

        What Jason Shirk suggested is closer to being useful. In the case of the other suggestions...

        New-ResourceGroup @{
        "ResourceGroupName" = $ResourceGroupName
        "Location" = $location
        "WhatIf" = $true
        "ErrorVariable" = "err"
        "ErrorAction" = "SilentlyContinue"
        }

        how would you the difference between that and actually passing a hashtable as an argument.

      • Jason Shirk [MSFT]Jason Shirk [MSFT] commented  ·   ·  Flag as inappropriate

        You can't use the (more or less) obvious syntax because that would change the meaning of scripts.

        We've discussed this in the past - with a proposed syntax of:

        Some-Command @@{
        Param = $Value
        }

        I read that as - splat ('@') a hash literal ('@{ ... ').

        The same could be done for an array, but I think that's much less useful.

      • Terry Wrennall (Black V)Terry Wrennall (Black V) commented  ·   ·  Flag as inappropriate

        OLD WAY
        ------------------------
        $splat = @{
        "ResourceGroupName" = $ResourceGroupName
        "Location" = $location
        "WhatIf" = $true
        "ErrorVariable" = "err"
        "ErrorAction" = "SilentlyContinue"
        }
        New-ResourceGroup @splat
        ------------------------

        NEW WAY
        ------------------------
        New-ResourceGroup @{
        "ResourceGroupName" = $ResourceGroupName
        "Location" = $location
        "WhatIf" = $true
        "ErrorVariable" = "err"
        "ErrorAction" = "SilentlyContinue"
        }
        ------------------------

      • Michael BMichael B commented  ·   ·  Flag as inappropriate

        Something that would allow a command like this

        New-ResourceGroup @{
        "ResourceGroupName" = $ResourceGroupName
        "Location" = $location
        "WhatIf" = $true
        "ErrorVariable" = "err"
        "ErrorAction" = "SilentlyContinue"
        }

      Feedback and Knowledge Base