Data/Generic/Invoke-GenericMethod.ps1

function Invoke-GenericMethod {
    ## Invoke a generic method on a non-generic type:
    ##
    ## Usage:
    ##
    ## ## Load the DLL that contains our class
    ## [Reflection.Assembly]::LoadFile("c:\temp\GenericClass.dll")
    ##
    ## ## Invoke a generic method on a non-generic instance
    ## $nonGenericClass = New-Object NonGenericClass
    ## Invoke-GenericMethod $nonGenericClass GenericMethod String "How are you?"
    ##
    ## ## Including one with multiple arguments
    ## Invoke-GenericMethod $nonGenericClass GenericMethod String ("How are you?",5)
    ##
    ## ## Ivoke a generic static method on a type
    ## Invoke-GenericMethod ([NonGenericClass]) GenericStaticMethod String "How are you?"
    ##

    param(
        $instance = $(throw "Please provide an instance on which to invoke the generic method"),
        [string] $methodName = $(throw "Please provide a method name to invoke"),
        [string[]] $typeParameters = $(throw "Please specify the type parameters"),
        [object[]] $methodParameters = $(throw "Please specify the method parameters")
    )

    ## Determine if the types in $set1 match the types in $set2, replacing generic
    ## parameters in $set1 with the types in $genericTypes
    function ParameterTypesMatch([type[]] $set1, [type[]] $set2, [type[]] $genericTypes) {
        $typeReplacementIndex = 0
        $currentTypeIndex = 0

        ## Exit if the set lengths are different
        if ($set1.Count -ne $set2.Count) {
            return $false
        }

        ## Go through each of the types in the first set
        foreach ($type in $set1) {
            ## If it is a generic parameter, then replace it with a type from
            ## the $genericTypes list
            if ($type.IsGenericParameter) {
                $type = $genericTypes[$typeReplacementIndex]
                $typeReplacementIndex++
            }

            ## Check that the current type (i.e.: the original type, or replacement
            ## generic type) matches the type from $set2
            if ($type -ne $set2[$currentTypeIndex]) {
                return $false
            }
            $currentTypeIndex++
        }

        return $true
    }

    ## Convert the type parameters into actual types
    [type[]] $typedParameters = $typeParameters

    ## Determine the type that we will call the generic method on. Initially, assume
    ## that it is actually a type itself.
    $type = $instance

    ## If it is not, then it is a real object, and we can call its GetType() method
    if ($instance -isnot "Type") {
        $type = $instance.GetType()
    }

    ## Search for the method that:
    ## - has the same name
    ## - is public
    ## - is a generic method
    ## - has the same parameter types
    foreach ($method in $type.GetMethods()) {
        # Write-Host $method.Name
        if (($method.Name -eq $methodName) -and
       ($method.IsPublic) -and
       ($method.IsGenericMethod)) {
            $parameterTypes = @($method.GetParameters() | ForEach-Object { $_.ParameterType })
            $methodParameterTypes = @($methodParameters | ForEach-Object { $_.GetType() })
            if (ParameterTypesMatch -set1 $parameterTypes -set2 $methodParameterTypes -genericTypes $typedParameters) {
                ## Create a closed representation of it
                $newMethod = $method.MakeGenericMethod($typedParameters)

                ## Invoke the method
                $newMethod.Invoke($instance, $methodParameters)

                return
            }
        }
    }

    ## Return an error if we couldn't find that method
    throw "Could not find method $methodName"
}