I have a command that returns a hash table. Like this one, for example:
function Get-TestArgs() { return @{a=1;b=2;c=3} }
And I'd like to use its return value as the arguments for my other function:
function Test($a, $b, $c) {
Write-Host 'A' $a
Write-Host 'B' $b
Write-Host 'C' $c
}
This is possible with PowerShell's splatting feature:
$testargs = @{a=1;b=2;c=3}
Test @testargs
The problem is I don't want to assign the hash to an intermediate variable.
Something along these lines is what I have in mind:
Test (some splat syntax)(Get-TestArgs)
Obviously, this wouldn't work, since it just creates an array containing the hash and passes that:
Test @(Get-TestArgs)
Is there a way to achieve this?
I am writing instructions that will be executed manually. These instructions will call out to scripts, but there is still some manual intervention to be done between calls. So I'd like to minimize the commands to reduce the risk of something going wrong, like a variable being leftover from other commands or a typo.
I don't think it's possible to use splatting without a variable. But there are few workarounds to achieve what you're looking for.
Write a wrapper function that would take a hashtable and invoke the 'real' function. If you wanted to call the function directly, without Get-TestArgs
, you would use TestInner
.
function Get-TestArgs() { return @{a=1;b=2;c=3} }
function TestInner ($a, $b, $c)
{
write-host "a=" $a
write-host "b=" $b
write-host "c=" $c
}
function Test ($hash) {
return TestInner @hash
}
Test (Get-TestArgs)
TestInner 1 2 3
Design your functions so that each takes a hashtable as the only parameter - it's a simplified version of 1. It looks a little ugly - you cannot determine the required parameters to Test
just by looking at its declaration.
function Test ($hash)
{
write-host "a=" $hash.a
write-host "b=" $hash.b
write-host "c=" $hash.c
}
Test (Get-TestArgs)
Use the approach from 2., but create a new type for the function parameter, to be a little more "type safe":
add-type -TypeDefinition @"
public class TestArg {
public int a = 0;
public int b = 0;
public int c = 0;
}
"@
function Get-TestArgs() { return new-object -type "TestArg" -Property @{a=1;b=2;c=3} }
function Test ([TestArg] $o)
{
write-host "a=" $o.a
write-host "b=" $o.b
write-host "c=" $o.c
}
Test (Get-TestArgs)
Take advantage of parameter sets and pipelines. This is similar to writing a wrapper, but the target function is also the wrapper - depending on the parameter set, it will either execute normally or use splatting to invoke itself again, but with different parameter set.
function Test {
param(
[Parameter(ParameterSetName="set1",Position=0)][int]$a,
[Parameter(ParameterSetName="set1",Position=1)][int]$b,
[Parameter(ParameterSetName="set1",Position=2)][int]$c,
[Parameter(ParameterSetName="pipeline",ValueFromPipeLine=$true,Position=0)][Hashtable]$obj
)
if ($obj -ne $null) { return Test @obj }
write-host "a=" $a
write-host "b=" $c
write-host "c=" $c
}
Test (Get-TestArgs)
Get-TestArgs | Test
Test 1 2 3
Depending on how many functions you need to create and how are you intend to invoke them, you could choose one of these solutions. Personally, the last one seems the most elegant choice to me. And I would go with pipes: Get-TestArgs | Test
looks more natural in PowerShell than Test (Get-TestArgs)
.
For example, many of Azure PowerShell commands are designed to work that way.
I'm fairly certain this can't be done with splatting because:
I really think the best you'll be able to do is:
function Test() {
param($a, $b, $c)
Write-Host 'A' $a
Write-Host 'B' $b
Write-Host 'C' $c
}
function Get-TestArgs() { @(1,2,3) }
$p = Get-TestArgs; Test @p
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With