cmdlet如何知道它何时应该调用WriteVerbose()?

时间:2010-05-05 17:18:56

标签: powershell

cmdlet如何知道真正何时应该调用WriteVerbose()WriteDebug()等等?

也许我想念一些简单的但我无法找到答案。所有cmdlet 到目前为止我看到的实现只是在没有任何情况下调用WriteVerbose() 犹豫。我知道这样做正确,但它不是有效

当详细模式关闭但cmdlet仍在准备时,性能会受到影响 WriteVerbose()来电的数据,即一无所获。

换句话说,在cmdlet中我希望能够:

if (<VerboseMode>)
{
    .... data preparation, sometimes expensive ...
    WriteVerbose(...);
}

但我不知道如何得到if (<VerboseMode>)。有什么想法吗?


结论: @ stej的答案显示了如何在理论上获得所需的信息。在实践中,这是hacky并且不太可能合适。因此,如果cmdlet产生非常昂贵的详细或调试输出,那么引入指定详细级别的附加参数似乎是合理的。

3 个答案:

答案 0 :(得分:6)

这是来自System.Management.Automation.MshCommandRuntime的方法。

internal void WriteVerbose(VerboseRecord record)
{
    if ((this.Host == null) || (this.Host.UI == null))
    {
        tracer.TraceError("No host in CommandBase.WriteVerbose()", new object[0]);
        throw tracer.NewInvalidOperationException();
    }
    ActionPreference verbosePreference = this.VerbosePreference;
    if (this.WriteHelper_ShouldWrite(verbosePreference, this.lastVerboseContinueStatus))
    {
        if (record.InvocationInfo == null)
        {
            record.SetInvocationInfo(this.MyInvocation);
        }
        this.CBhost.InternalUI.WriteVerboseRecord(record);
    }
    this.lastVerboseContinueStatus = this.WriteHelper(null, null, verbosePreference, this.lastVerboseContinueStatus, "VerbosePreference");
}

MshCommandRuntime实现了接口ICommandRuntime,它对详细程度一无所知:| (通过反射器找到)。 MshCommandRuntime的{​​{1}}实例应该在Cmdletpublic ICommandRuntime CommandRuntime { get; set; })中提供。

因此,应该可以将属性CommandRuntime强制转换为MshCommandRuntime并检查详细程度。无论如何,这真的很难看。


我完全同意应该有一个简单的方法来找到它。除此之外(做梦)编译器应该足够聪明,不要在这样的情况下评估一些字符串:

$DebugPreference = 'SilentlyContinue'
$array = 1..1000
Write-Debug "my array is $array"

永远不会使用Write-Debug的输入,因此不应在传递的字符串中评估$array ..(可以测试它是否真的像这样评估:Write-Debug "my array is $($array|%{write-host $_; $_})"

答案 1 :(得分:5)

因此,我们不仅需要考虑cmdlet的公共参数-Debug和-Verbose,还要考虑全局$ DebugPreference和$ VerbosePreference标志,以及如果从中调用cmdlet,则继承这些公共参数的事实另一个cmdlet。

可以在内部进行黑客攻击。

This answer向您展示了PowerShell cmdlet中可以解决的问题。

function f { [cmdletbinding()]Param() 
    $debug = $DebugPreference -ne 'SilentlyContinue'
    $verbose = $VerbosePreference -ne 'SilentlyContinue'
    "f is called"
    "    `$debug = $debug"
    "    `$verbose = $verbose"
}
function g { [cmdletbinding()]Param() 
    "g is called"
    f 
}
f
f -Debug -Verbose
g
g -Debug -Verbose

从C#开始,我们必须检查这些全局标志,以及常用参数。一定要继承PSCmdlet而不是Cmdlet来获取GetVariableValue方法。

bool debug = false;
bool containsDebug = MyInvocation.BoundParameters.ContainsKey("Debug");
if (containsDebug)
    debug = ((SwitchParameter)MyInvocation.BoundParameters["Debug"]).ToBool();
else
    debug = (ActionPreference)GetVariableValue("DebugPreference") != ActionPreference.SilentlyContinue;

bool verbose = false;
bool containsVerbose = MyInvocation.BoundParameters.ContainsKey("Verbose");
if (containsVerbose)
    verbose = ((SwitchParameter)MyInvocation.BoundParameters["Verbose"]).ToBool();
else
    verbose = (ActionPreference)GetVariableValue("VerbosePreference") != ActionPreference.SilentlyContinue; 

答案 2 :(得分:4)

怎么样:

BEGIN {
    if ($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) {
        $HasDebugFlag = $true
    }

    if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
        $HasVerboseFlag = $true
    }
}
PROCESS {
    if ($HasVerboseFlag) {
        expensive_processing
    }
}

警告:仅在PowerShell 3上测试。