Private/Invoke-ISPlugins.ps1

<#
.SYNOPSIS
    Invokes a list of plugins, passing along a hashtable of arguments
.DESCRIPTION
    The Invoke-ISPlugins cmdlet will run a list of plugins and pass along a hashtable of arguments, returning whatever the plugins would return.
.EXAMPLE
    $Arguments = @{
        Node = $XmlNode
        InstanceName = "SomeInstanceName"
        ComponentDirectory = "PathToComponentDirectory"
        InstanceDirectory = "PathToInstanceDirectory"
    }
    Invoke-ISPlugins -Plugins $Plugins -Arguments $Arguments
.PARAMETER Plugins
    A list of plugins to invoke
.PARAMETER Arguments
    A hashtable with arguments for the plugin.
#>

function Invoke-ISPlugins
{
    param (
        [parameter(
            Mandatory = $true,
            Position = 0
        )]
        [ValidateScript( {Test-Path -Path $_.Path -PathType Leaf})]
        [PSObject[]] $Plugins,

        # Arguments to pass to the plugins
        [Parameter(
            Mandatory = $true,
            Position = 1
        )]
        [hashtable]$PluginArguments
    )

    foreach ($Plugin in $Plugins)
    {
        Write-Verbose "Running plugin $($Plugin.Name)"
        $PluginModule = Import-Module -Name $Plugin.Path -PassThru -Force -WarningAction:SilentlyContinue

        try {
            $CommandBlock = $PluginModule.ExportedCommands[($Plugin.Name)].ScriptBlock
        }
        catch {
            Throw "Could not find plugin scriptblock. Plugin not valid."
        }
        
        try
        {
            InvokePlugin $CommandBlock $PluginArguments
        }
        catch
        {
            Write-Error -Message $_.Exception -ErrorAction:Continue
        }
        finally
        {
            $PluginModule | Remove-Module -Force -ErrorAction:SilentlyContinue
        }
    }
}

function InvokePlugin ($ScriptBlock, $Arguments)
{
    $ScriptBlock.Invoke($PluginArguments.Node, $PluginArguments.InstanceName, $PluginArguments.InstanceDirectory, $PluginArguments.ComponentDirectory)
}