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

Powershell cmdlet如何知道何时真正应该调用WriteVerbose()?,powershell,Powershell,cmdlet如何知道何时真正应该调用WriteVerbose(), WriteDebug()等等 也许我错过了一些简单的事情,但我找不到答案。所有cmdlet 到目前为止,我看到的实现只是调用WriteVerbose(),而没有任何 犹豫。我知道这样做是正确的,但没有效果 当关闭详细模式但cmdlet仍在准备时,性能会受到影响 WriteVerbose()调用的数据,也就是说,是免费的 换句话说,在cmdlet中,我希望能够: if (<VerboseMode>) { ...

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

也许我错过了一些简单的事情,但我找不到答案。所有cmdlet 到目前为止,我看到的实现只是调用
WriteVerbose()
,而没有任何 犹豫。我知道这样做是正确的,但没有效果

当关闭详细模式但cmdlet仍在准备时,性能会受到影响
WriteVerbose()
调用的数据,也就是说,是免费的

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

if (<VerboseMode>)
{
    .... data preparation, sometimes expensive ...
    WriteVerbose(...);
}
if()
{
…数据准备,有时很昂贵。。。
WriteVerbose(…);
}
但是我不知道如何得到这个
if()
。有什么想法吗


结论:
@stej的回答从理论上说明了如何获得所需的信息。在实践中,这是老套的,不太合适。因此,如果cmdlet生成非常昂贵的详细或调试输出,那么引入一个指定详细级别的附加参数似乎是合理的。

这是来自
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
的实例应在
Cmdlet
public-ICommandRuntime-CommandRuntime{get;set;}
)中可用

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


我完全同意应该有一个简单的方法来找到它。除此之外,(梦想)编译器应该足够聪明,不会在如下情况下计算某些字符串:

$DebugPreference = 'SilentlyContinue'
$array = 1..1000
Write-Debug "my array is $array"
将永远不会使用
写入调试的输入,因此不应在传递的字符串中计算
$array
。。(可以测试它是否真的是这样计算的:
Write Debug“我的数组是$($array |%{Write host$\u;$\ u})”
怎么样:

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

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

警告:仅在PowerShell 3上测试。

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

它可以在不破坏内部结构的情况下完成

向您展示了它可以在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; 

@谢谢你的有用的调查。理论上,用反射的方式进行黑客攻击应该是可能的(因为大多数东西都是内部的,不能正常访问)。但这当然不是一个切实可行的解决方案。不过,如果我们没有找到更好的替代方案,我会在一段时间内接受答案。我还在Connect上找到了一个相关建议:(我认为这还不够;我们需要一个标志IsVerbose、IsDebug等。)@Roman,投了票。|我现在想到的是-在开发cmdlet时,你应该可以访问所有变量,不是吗。然后就可以获得
$DebugPreference
,并据此采取行动。这不理想,但应该可以工作。
$DebugPreference
$verbosepference
确实比没有好。但它们不是这还不够,因为它们被cmdlet泛在参数
-Verbose
-Debug
覆盖(如果有指定)。但是这些参数无法从cmdlet访问。参数是否会隐式更改本地
$DebugPreference
$VerbosePreference
?我对此表示怀疑,但我会尝试找出答案。无处不在的参数是否会更改本地
$DebugPreference
$VerbosePreference
–不,他们没有。好吧,基本上我得出的结论是,如果出现昂贵的详细或调试输出,cmdlet应该引入额外的开关甚至参数,有点像
-VerboseLevel
。嗯,事实上,这也许不是个坏主意。是的,在一些脚本中我正是这样使用的。更详细的级别可以得到我想要的我想要。除此之外..我去掉了“VERBOSE:”和“DEBUG:”前缀。这确实很好。+1.这在某些情况下应该有效,事实上,很多情况下。如果模式不是由参数设置的,而是通过
$verboseproperty
$DebugPreference
设置的,那么它将不起作用。因此,
if
-s也应该检查这些变量。但V3引入了自定义默认值。如果通过自定义默认值启用模式,则绑定参数可能没有帮助。如果从一个cmdlet调用另一个cmdlet,则绑定参数不起作用。我不同意您的结论。有关解决方案,请参阅我的答案。