views:

284

answers:

3

With custom Powershell functions all function output is returned. I'm attempting to remove that limitation/confusion by writing a wrapper function that will return just $true or $false.

However, I'm struggling with the dynamic function call . . . specifically passing the arguments.

Note that both the function name and the function arguments are passed to "ExecBoolean".

Code Sample:

# Simplifies calls to boolean functions in Powershells scripts
# Helps solve this problem -> http://www.vistax64.com/powershell/107328-how-does-return-work-powershell-functions.html

function Foo([string]$sTest, [int] $iTest)
{
    Write-Host "sTest [" $sTest "]."
    Write-Host "iTest [" $iTest "]."
    if ($iTest -eq 1)
    {
        return $true
    }
    else
    {
        return $false
    }
}

function ExecBoolean ([string] $sFunctionName, [array] $oArgs)
{   
    Write-Host "Array Length = " $oArgs.Length ", Items = [" $oArgs[0..($oArgs.Length - 1)] "]"

    $oResult = & $sFunctionName $oArgs[0..($oArgs.Length - 1)]

    # Powershell returns all function output in oResult, just get the last item in the array, if necessary.                     
    if ($oResult.Length -gt 0) 
    {
        return $oResult[$oResult.Length - 1]
    } 
    else 
    {
        return $oResult
    }
}

$oResult = ExecBoolean "Foo" "String1", 1

Write-Host "Result = " $oResult

Current Output:

Array Length =  2 , Items = [ String1 1 ] 
sTest [ String1 1 ]. 
iTest [ 0 ]. 
Result =  False

Desired Output:

Array Length =  2 , Items = [ String1 1 ]
sTest [ String1 ].
iTest [ 1 ].
Result =  True

Is this possible in Powershell v1.0?

Thanks.

A: 
$oResult = & $sFunctionName $oArgs[0..($oArgs.Length - 1)]

Here you're passing the function only one argument —an array— so the second parameter in Foo defaults to 0.

If you just want to discard output from a statement/expression, there are ways to do so, like piping it to Out-Null or "casting" to void.

guillermooo
Thanks, yes, I understand what is happening. I thought/hoped that $oArgs[0..($oArgs.Length - 1)] would not be considered an array, but a list of arguments 0, 1, 2, etc.I know the "out-null" trick but I'm trying to avoid the problems that ensue when developers forget to use it or just don't know that which statements return output.
MattH
A: 

I would use Invoke-Expression like this:

function ExecBoolean ([string] $sFunctionName)
{   
    Write-Host "Array Length = " $args.Length ", Items = [" $args[0..($args.Length - 1)] "]"
    $oResult = Invoke-Expression "$sFunctionName  $($args -join ' ')"
    # Powershell returns all function output in oResult, just get the last item in the array, if necessary.                     
    if ($oResult.Length -gt 0) 
    {
        return $oResult[$oResult.Length - 1]
    } 
    else 
    {
        return $oResult
    }
}
ExecBoolean Foo String1 1

Note that:

  1. I use $args which is imho more comfortable, because you don't to pass the arguments as a array. However, you could use your $oArgs as well with no problem (the only line that matters is the one with Invoke-Expression).
  2. This will work only for simple types (strings, ints, ...), but not for e.g. FileInfo, because the objects are converted to strings in $($args -join ' ').
  3. There is one more option, but it is too verbose: ExecBoolean Foo @{sTest="String1"; iTest=1}. So you would pass parameters in a hashtable. You would need to alter Foo to accept hashtable of course. In this case you could pass any type in, because you could call Foo using & operator.
  4. See below

I would not recommend this approach, because of the limitations (but it can happen that maybe others will come up with better solution).
If you just want to ensure that no output is returned from Foo, you might create a script that parses other scripts that call Foo and checks that every call to "Foo" must be prepended with $null =.

If you switch to PowerShell V2, there is better way called splatting. For more info look at How and Why to Use Splatting (passing [switch] parameters)

stej
A: 

Personally, I would just use:

functionName -as [bool]

This will coerce the results of the function into a boolean.

It's much more readable later on.

Hope this helps

Start-Automating
In your experience, does it reliably coerce boolean results even when the function has other output?
MattH