none
Howto use the splatting operator on a nested hashtable within a foreach-loop without a temp variable RRS feed

  • Question

  • Hi Guys,

    consider this simple nested hashtable

    $items = @{
    	
    	"First" = @{
    		"Parameter1" = "Value1"
    		"Parameter2" = "Value2"
    	}
    	
    	"Second" = @{
    		"Parameter1" = "Value1"
    		"Parameter2" = "Value2"
    	}
    }

    If I want to pass the values into a function using the splatting (@) operator, I have to use something like this:

    foreach($item in $items.GetEnumerator())
    {
    	$currentItem = $item.Value
    	Write-Host @currentItem
    }

    Do I really need a temp variable (currentItem)? I tryed something like this:

    foreach($item in $items.GetEnumerator())
    {
        Write-Host @item.Value # doesn't work.
        Write-Host @($item.Value) # doesn't work.
    }

    Thursday, September 11, 2014 11:50 AM

Answers

  • As far as I can tell, the answer is "No".

     Seems to be a limitation of what the operator can accept as an argument.  I agree it's not very intuitive, but I wouldn't consider it an onerous requirement in exchange for the functionality the operator provides.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    • Marked as answer by JisaakMVP Thursday, September 11, 2014 12:34 PM
    Thursday, September 11, 2014 12:31 PM
    Moderator

All replies

  • Splatting only works with simple variables, so you really do need that temp variable.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "


    Thursday, September 11, 2014 12:16 PM
    Moderator
  • Oh, you are right. I didn't found that thread. So the answer is no?!
    Thursday, September 11, 2014 12:19 PM
  • Why?

    What does this gain for you?

    THe demo is also incorrect as Write-Host cannot use that splat because it means nothing to that CmdLet.

    Splatting must bind to known Parmeters.

    "Write-Host" can only use: Object, BackgroundColor, ForegroundColor, NoNewline

    Splatting with any names not supported will not work and will cause an error.

    Example:

    PS C:\scripts> $p=@{Object='Hello world';ForeGroundColor='red'}
    PS C:\scripts> Write-Host @p
    Hello world
    PS C:\scripts> $p=@{Object='Hello world';ForeGroundColor='red';Dummy='xxx'}
    PS C:\scripts> Write-Host @p
    Write-Host : A parameter cannot be found that matches parameter name 'Dummy'.
    At line:1 char:12
    + Write-Host @p
    +            ~~
        + CategoryInfo          : InvalidArgument: (:) [Write-Host], ParameterBindingException
        + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.WriteHostCommand
    
    PS C:\scripts>

    To pass a hash of parameters use variables.


    ¯\_(ツ)_/¯

    Thursday, September 11, 2014 12:25 PM
  • As far as I can tell, the answer is "No".

     Seems to be a limitation of what the operator can accept as an argument.  I agree it's not very intuitive, but I wouldn't consider it an onerous requirement in exchange for the functionality the operator provides.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    • Marked as answer by JisaakMVP Thursday, September 11, 2014 12:34 PM
    Thursday, September 11, 2014 12:31 PM
    Moderator
  • Here is a simple example of passing a hash to a function then using it as a splat.

    $p=@{
    	MyParam=@{Object='Hello World';Fore='green'}
    }
    
    function MyTest{
    	Param(
    		$MyParam
    	)
    	
    	Write-Host @MyParam
    }
    MyTest @p
    

    Copy and paste to PowerShell CLI and you will see that it works as expected.


    ¯\_(ツ)_/¯

    • Proposed as answer by jrv Thursday, September 11, 2014 12:38 PM
    Thursday, September 11, 2014 12:37 PM
  • Why? Because I don't want to introduce unnecessary variables to use splatting. 

    I know that Splatting must bind to known Paramters. The demo isn't incorrect - it demonstrates my problem well.

    Thursday, September 11, 2014 12:41 PM
  • Example of passing a hash splat of hashes to splat with:

    $p=@{ MyParam=@{ A=@{Object='Hello World';Fore='red'} B=@{Object='Goodbye Old World';Fore='green'} } }
    function MyTest{ Param( $MyParam ) $p=$MyParam['A'] Write-Host @p $p=$MyParam['B'] Write-Host @p } MyTest @p



    ¯\_(ツ)_/¯

    Thursday, September 11, 2014 12:49 PM
  • This is not what im looking for. 
    Thursday, September 11, 2014 12:53 PM
  • A practical example:

    $p=@{
    	MyParam=@{
    		       Running=@{Object='Service is running';Fore='green'}
    		       Stopped=@{Object='WARNING:Service down!';Fore='red'}
    	}
    }
    function Check-Service{
    	Param(
    	    [Parameter(ValueFromPipeLine=$true)]
    	    [object]$service,
    		$MyParam
    	)
    	Process{
    		$p=$MyParam[$service.Status.ToString()]
    		Write-Host @p
    	}
    }
    Check-Service @p (Get-Service alg)
    Get-Service | Check-Service @p


    ¯\_(ツ)_/¯

    Thursday, September 11, 2014 1:10 PM
  • In my examples @p is the name of a hash tagged and passed as a splat.  The splat only wants the variable name and not the variable.  The hash will be retrieved and merged into $PSBoundParameters before the function is executed.

    The name is the one used in Get-Variable like this:

    Get-Variable p

    You cannot use a variable to specify a hash so

    @($p.A)

    Will not work because the test after the '@' is the name of a hash.  @() is an array specifier. @p.A is nothing.

    We must assign the hash to a simple variable which can be used as a Splat.


    ¯\_(ツ)_/¯

    Thursday, September 11, 2014 1:21 PM