多次覆盖函数以进行继承调用堆栈记录

Override functions multiple times for inheritant call stack logging

让我们假设以下 CmdLets:

Write-MyColl

function Write-MyColl {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [psobject] $InputObject
    )

    $verb = Get-Command Write-Verbose
    $fixedName = $PSCmdlet.MyInvocation.InvocationName
    function Write-Verbose ($Object) {
        & $verb "[$fixedName] $Object"
    }

    if ($InputObject.name) {
        Write-Verbose "Writing `$InputObject's Name: `"$($InputObject.name)`""
    }
}

New-MyColl

function New-MyColl {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string[]] $Names
    )

    $verb = Get-Command Write-Verbose
    $fixedName = $PSCmdlet.MyInvocation.InvocationName
    function Write-Verbose ($Object) {
        & $verb "[$fixedName] $Object"
    }

    Write-Verbose "Names: $Names"
    foreach ($name in $Names) {
        @{
            id = 123;
            name = $name
        } | Write-MyColl
    }
}

如您所见,New-MyColl 用它自己的 Write-Verbose 覆盖了 Microsoft.PowerShell.Utility\Write-Verbose。这完美地工作并输出:

VERBOSE: [New-MyColl] Names: [...]

现在,当调用 Write-MyColl 时,它 应该 覆盖 New-MyColl 中的 Function:\Write-Verbose 并且我希望它输出如下内容:

VERBOSE: [New-MyColl] [Write-MyColl] Writing `$InputObject's Name: "[...]"

正如您可能已经想到的那样,它不起作用。 Write-Verbose 递归调用自身直到天数结束。我已经尝试过局部函数定义和局部变量,但它们对调用的 CmdLet 不可见。

我认为对于我的特定用例,我将使用 Get-PsCallStack,但是我希望看到一个解决方案来覆盖如上所述的重写函数。

我很难理解的是,为什么第二个Write-Verbose调用了自己,所以$verb貌似指向了一个尚未定义的函数。它不应该指向先前定义的函数吗?我已经尝试 Remove-Item 脚本末尾的功能,但它没有改变任何东西。

你知道如何实现这个调用堆栈行为吗?

感谢,我得到了以下解决方案:

New-Item function::local:Write-Verbose -Value (
    New-Module -ScriptBlock { param($verb, $fixedName, $verbose) } -ArgumentList @(
        (Get-Command Write-Verbose), 
        $PSCmdlet.MyInvocation.InvocationName, 
        $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent
    )
).NewBoundScriptBlock{
    param($Message)
    if ($verbose) {
        & $verb -Message "=>$fixedName $Message" -Verbose
    } else {
        & $verb -Message "=>$fixedName $Message"
    }
} | Write-Verbose

-Verbose参数没有传递给新创建的函数;这就是我将它添加到 -ArgumentList 的原因。我敢肯定,它不是很漂亮,但它确实做了它应该做的。每次调用覆盖Write-Verbose

现在输出如下:

VERBOSE: =>[New-MyColl] Names: [...]
VERBOSE: =>[New-MyColl]=>[Write-MyColl] Writing `$InputObject's Name: "[...]"