如何将-Verbose传递给模块函数?

10
根据这个答案和我的经验,PowerShell可以自动传播-Verbose(和-Debug),这非常方便。但是,当我想要传播详细信息的函数在模块中时,它就不起作用了。用于测试的代码如下:
创建一个名为Mod的目录,在c:中添加2个文件:
文件c:\Mod\Functions.ps1:
function Show-VerbosityB { [cmdletbinding()]Param()
  Write-Output "Show-VerbosityB called"
  Write-Verbose "Show-VerbosityB is Verbose"
}

文件 c:\Mod\Mod.psd1:

@{
ModuleVersion = '1.0.0.0'
NestedModules = @('Functions.ps1')
FunctionsToExport = @('*-*')
}

现在创建主脚本,命名为c:\Foo.ps1
Import-Module c:\Mod

function Show-VerbosityA { [cmdletbinding()]Param()
  Write-Output "Show-VerbosityA called"
  Write-Verbose "Show-VerbosityA is Verbose"
}

function Show-Verbosity { [cmdletbinding()]Param()
  Write-Output "Show-Verbosity called"
  Write-Verbose "Show-Verbosity is Verbose"
  Write-Output "Testing propagation"
  Show-VerbosityA
  Show-VerbosityB
}

Show-Verbosity -Verbose

结果在

PS> . C:\Foo.ps1
Show-Verbosity called
VERBOSE: Show-Verbosity is Verbose
Testing propagation
Show-VerbosityA called
VERBOSE: Show-VerbosityA is Verbose
Show-VerbosityB called

模块函数中的Write-Verbose为什么被跳过了?为什么传播行为不像Show-VerbosityA那样?(如果我只是用点运算符引用Functions.ps1,那么VERBOSE: Show-VerbosityB is Verbose这一行就会被打印出来)。我可以通过手动调用Show-VerbosityB -Verbose:$PSBoundParameters['Verbose']等方式进行传递。或者是否有其他更短的方法?如果函数行为因为是模块的一部分而与直接引用有所不同,那么这就非常混乱。
2个回答

12
这是发生的原因是因为在调用该模块时未传播$VerbosePreference。我修改了您的脚本,明确地打印与您通过Write-VerboseWrite-Output输出相同的值。
这篇powershell.org帖子提出了将此添加到模块中的建议,对我非常有用:
if (-not $PSBoundParameters.ContainsKey('Verbose'))
{
    $VerbosePreference = $PSCmdlet.GetVariableValue('VerbosePreference')
}

其中一条评论提到了带有链接的错误报告(该链接不存在或我没有权限查看)

这个问题在TechNet的一篇帖子中讨论过,并提供Get-CallerPreferance函数的链接来解决此问题。


模块:

function Show-VerbosityB { [cmdletbinding()]Param()

    <# uncomment to get verbose preference from caller, when verbose switch not explicitly used.
    if (-not $PSBoundParameters.ContainsKey('Verbose'))
    {
        $VerbosePreference = $PSCmdlet.GetVariableValue('VerbosePreference')
    }
    #>

    Write-Output "`nShow-VerbosityB called"
    Write-output "Global pref: $($global:VerbosePreference)"
    Write-output "Script pref: $($script:VerbosePreference)"
    Write-output "Effect pref: $VerbosePreference"
    Write-Verbose "Show-VerbosityB is Verbose"
}

来电者:

Import-Module C:\Mod

Write-output "On startup: $VerbosePreference"

function Show-VerbosityA { [cmdletbinding()]Param()
  Write-Output "`nShow-VerbosityA called"
  Write-output "Global pref: $($global:VerbosePreference)"
  Write-output "Script pref: $($script:VerbosePreference)"
  Write-output "Effect pref: $VerbosePreference"
  Write-Verbose "Show-VerbosityA is Verbose"
}

function Show-Verbosity { [cmdletbinding()]Param()
  Write-Output "`nShow-Verbosity called"
  Write-output "Global pref: $($global:VerbosePreference)"
  Write-output "Script pref: $($script:VerbosePreference)"
  Write-output "Effect pref: $VerbosePreference"
  Write-Verbose "Show-Verbosity is Verbose"
  Write-Output "`nTesting propagation"
  Show-VerbosityA
  Show-VerbosityB
}

Show-Verbosity -Verbose

2
谢谢,这确实是答案。不幸的是,不完全是我所希望的:] 修改每个函数来处理这个问题是疯狂的,所以如果我需要所有冗长,我可能会转而使用类似 $global:VerbosePreference = [System.Management.Automation.ActionPreference] :: Continue 的东西。 - stijn
全局变量很丑陋。调用链接的 Get-CallerPreferance 函数只需要一行代码。对我来说,让我的模块函数像内置的 cmdlet 一样运行,而无需在调用方担心,则是值得的。 - zett42
奇怪,这对我不起作用(Get-CallerPreference等)。$PSCmdlet的值存在,但是一旦我从另一个psm1调用函数,那个psm1中的函数会将$PSCmdlet视为null... - DaveUK
1
没关系!我的问题是我没有在其他psm1中的函数上指定[cmdletbinding()]param。添加cmdletbinding()使$PSCmdlet变量起作用。 - DaveUK
更准确地说,例如 VerbosePrefreenceDebugPreferenceWhatIfPreference 这样的东西可能无法在不同 脚本 模块中的函数之间正确传播。 微软已经意识到这个问题,并且一直在尝试修复这种不一致的行为。 - fourpastmidnight

1
如果您想从调用脚本中设置,尝试这样做:
(Get-Module 'ModuleName').SessionState.PSVariable.Set('Global:VerbosePreference', $VerbosePreference)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接