# encoding: ascii
# api: powershell
# title: push-module function v2 
# description: push-module will import a powershell v2.0 module and ensure that when the module is removed using remove-module, the functions the module clobbered are restored. UPDATE: previous version restored (promoted to global scope) clobbered functions that were visible from push-module function scope; this is wrong – it should only restore global functions.
# version: 2.0
# type: function
# author: Oisin Grehan
# license: CC0
# function: Push-Module
# x-poshcode-id: 1773
# x-archived: 2010-04-17T07:55:56
#
#
# v2.0

function Push-Module {
    param(
        [parameter(position=0, mandatory=$true)]
        [validatenotnullorempty()]
        [string]$ModuleName
    )
    
    # find out what this module exports (and therefore what it overwrites)
    $metadata = new-module -ascustomobject {
        param([string]$ModuleName)
        
        # import targeted module
        $inner = import-module $ModuleName -PassThru       
        function GetExportedFunctions() {
            $inner.ExportedFunctions.values
        }
        
        # prevent export of inner module's exports
        Export-ModuleMember -Cmdlet "" -Function GetExportedFunctions
        
    } -args $ModuleName
        
    # find out which global functions might get clobbered
    $test = new-module -ascustomobject {
        param($metadata)
        
        $clobbered = @{}
        
        # grab copies of functions that would get clobbered
        $metadata.GetExportedFunctions() | ? {
            Test-Path "function:$($_.name)"
        } | % {    
            $clobbered[$_.name] = gc -path "function:$($_.name)"
        }
        
        function GetClobberedFunctions() {
            $clobbered
        }
        
    } -args $metadata

    # import module
    $m = import-module $ModuleName -PassThru

    # grab clobberable (!) functions
    $clobbered = $test.GetClobberedFunctions()
        
    # hook up function restore
    $m.onremove = {
        $clobbered.keys | % {
            si -path function:global:$_ $clobbered[$_] -force
        }
    }.getnewclosure()
}
