为继承调用堆栈日志记录多次覆盖函数

时间:2017-08-30 14:09:32

标签: windows powershell scope override powershell-v5.0

我们假设以下CmdLets:

写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)`""
    }
}

新-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会覆盖Microsoft.PowerShell.Utility\Write-Verbose并使用它自己的Write-Verbose。这完美地运作并输出:

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

现在,当Write-MyColl被调用时,应该覆盖Function:\Write-Verbose的{​​{1}},我希望它输出如下内容:

New-MyColl

正如您可能已经想到的那样,它不起作用。 VERBOSE: [New-MyColl] [Write-MyColl] Writing `$InputObject's Name: "[...]" 以递归方式调用自己,直到几天结束。我已经尝试过本地函数定义和局部变量,但它们对调用的CmdLet不可见。

我认为对于我的具体用例,我会使用Get-PsCallStack,但我很乐意看到一个解决方案来覆盖上面描述的覆盖函数。

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

您是否知道如何实现 call-stack-behavior

1 个答案:

答案 0 :(得分:0)

感谢PetSerAI's comment,我找到了以下解决方案:

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: "[...]"