Search code examples
powershellparameter-passingindirection

Invoking a function indirectly, via a variable containing the function name


I'm importing a XML node to the variable XmlInstallNode and then dynamically building the function I want to call.

Everything works great if I call the function directly by its name, but If called it in the invoke command using the $functionName, then the parameter -App - is converted to string when it is supposed to be a System.Xml.XmlLinkedNode. I have already tried to cast it and use different approaches with the Invoke-Expressions and Invoke-Command without success...

I get this error, which kinda makes sense: Cannot process argument transformation on parameter 'App'. Cannot convert the "$app" value of type "System.String" to type "System.Xml.XmlElement"

function global:XtrInstall{
try
{
    $error=$false
    XtrLog -Level INFO -FunctionName $MyInvocation.MyCommand -Msg "Installing Apps..."

    XtrLog -Level DEBUG -FunctionName $MyInvocation.MyCommand -Msg "Getting available Apps from config file."
    $XmlInstallNode=XtrGet-XmlInstall

    if($XmlInstallNode.Apps)
    {        
        foreach($app in $XmlInstallNode.apps.app)
        {
            $functionName = "$("XtrInstall-")$($app.Name)"
            XtrLog -Level DEBUG -FunctionName $MyInvocation.MyCommand -Msg "$("Building function name: ")$($functionName)"

            if (Get-Command $functionName -errorAction SilentlyContinue)
            {
                XtrLog -Level DEBUG -FunctionName $MyInvocation.MyCommand -Msg "$("Invoking App Install function ")$($functionName)"
                $command = "$($functionName)$(" -App")"
                $error = Invoke-Command -ScriptBlock { Invoke-Expression -Command $command} -ArgumentList $app                    
            }
            else
            {
                XtrLog -Level FATAL -FunctionName $MyInvocation.MyCommand -Msg "$("App Install Function " )$($functionName)$(" not found. See App name (e.g.'XtrInstall-Aplication')")"
                return $true
            }
        }
    }
    else
    {
        XtrLog -Level WARN -FunctionName $MyInvocation.MyCommand -Msg "No Apps detected in Config file."
        $error=$true
    }
}
catch
{
    XtrLog -Level FATAL -FunctionName $MyInvocation.MyCommand -Msg $_.Exception.Message
    $error=$true
}
return $error
}

The function I'm calling is:

    function global:XtrInstall-Filesite()
    {
    Param(
        [Parameter(Mandatory=$true)]
        [Xml.XmlElement]$App
    )
        //DO STUFF
    }

How can I pass the parameter as it is ?


Solution

  • There is no need for building a (partial) command in a string and using Invoke-Expression, or even Invoke-Command.

    Try the following instead:

    $error = & $functionName -App $app                    
    
    • &, PowerShell's call operator, can be used to invoke any command whose name is stored in a variable.
      • (You also need it to invoke an external utility with a path that must be quoted due to containing spaces or other characters with special meaning; e.g.,
        & 'c:\path\to\some folder\some.exe').