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