Public/New-PSCallTraceHook.ps1

#Todo Fix Begin Process and End Error when Piping into a hooked function.

function New-PSCallTraceHook {
    <#
        .Synopsis
        New-PSCallTraceHook hooks an existing PowerShell function in this session in order to properly generate callback data.
        .Description
        New-PSCallTraceHook -Name Write-Host -Module Microsoft.PowerShell.Utility
        .Example
        . {
            New-PSCallTraceHook -Name Write-Host -Module Microsoft.PowerShell.Utility
            Write-Host "My String"
            Get-PSCallTrace | ft
        }
    #>

    [CmdletBinding()]
    param(
        [Parameter(Position = 0, Mandatory)]
        [String]$Name,
        [Parameter()]
        [String]$Module = "PSCallTraceHook",
        [Parameter()]
        [Switch]$DisableParamMirroring
    )
    if ($Module -eq "PSCallTraceHook") {
        if (Test-Path ("Function:{0}\{1}" -f $Module, $Name)) {
            Throw "Cannot Hook Function, It looks like it is already hooked"
        }
        Rename-Item -Path "Function:Global:$Name" -NewName ("Global:{0}\{1}" -f $Module, $Name)
    }
    $MetaData = New-Object System.Management.Automation.CommandMetaData (Get-Command "$Module\$Name")
    $HookedFunction = [System.Management.Automation.ProxyCommand]::Create($MetaData)

    $HookedFunction = $HookedFunction.Replace("`$steppablePipeline.Begin(`$myInvocation.ExpectingInput, `$ExecutionContext)", "`$Result = Invoke-PSCallTrace -Begin -Hook `$steppablePipeline.Begin -Arguments (`$myInvocation.ExpectingInput, `$ExecutionContext); `$PSCallTrace = `$Result.Message; `$Result.Result")
    $HookedFunction = $HookedFunction.Replace("`$steppablePipeline.Begin(`$PSCmdlet)", "`$Result = Invoke-PSCallTrace -Begin -Hook `$steppablePipeline.Begin -Arguments `$PSCmdlet; `$PSCallTrace = `$Result.Message; `$Result.Result")
    $HookedFunction = $HookedFunction.Replace("`$steppablePipeline.Process(`$_)", "Invoke-PSCallTrace -Object `$PSCallTrace -Process -Hook `$steppablePipeline.Process -Arguments `$_")
    $HookedFunction = $HookedFunction.Replace("`$steppablePipeline.End()", "Invoke-PSCallTrace -Object `$PSCallTrace -End -Hook `$steppablePipeline.End")

    if (Test-Path Function:$Name) {
        Set-Item -Path Function:Global:$Name -Value $HookedFunction | out-null
    } else {
        New-Item -Path Function: -Name "Global:$Name" -Value $HookedFunction | out-null
    }
}