How does a cmdlet know when it really should call WriteVerbose()
,
WriteDebug()
and etc.?
Perhaps I miss something simple but I cannot find the answer. All cmdlet
implementations I have seen so far just call WriteVerbose()
without any
hesitation. I know that it is correct to do so, but it is not effective.
Performance suffers when verbose mode is off but a cmdlet still prepares
data for WriteVerbose()
call, that is, for nothing.
In other words, in a cmdlet I would like to be able to:
if (<VerboseMode>)
{
.... data preparation, sometimes expensive ...
WriteVerbose(...);
}
But I don't know how to get this if (<VerboseMode>)
. Any ideas?
Conclusion: The @stej’s answer shows how get the required information in theory. In practice this is hacky and unlikely suitable. Thus, if a cmdlet produces really expensive verbose or debug output then it looks reasonable to introduce an additional parameter specifying verbosity levels.
This is method from 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
implements interface ICommandRuntime
which doesn't know anything about verbosity :| (found through reflector). Instance of MshCommandRuntime
should be available in Cmdlet
(public ICommandRuntime CommandRuntime { get; set; }
).
So it should be possible to cast property CommandRuntime
to MshCommandRuntime
and check the verbosity. Anyway, this is really ugly.
I totally agree that there should be an easy way how to find it out. And besides that (dreaming) compiler should be clever enough not to evaluate some strings in cases like this:
$DebugPreference = 'SilentlyContinue'
$array = 1..1000
Write-Debug "my array is $array"
Input to Write-Debug
will be never used, so $array
shouldn't be evaluated in passed string.. (it is possible to test that it is really evaluated like this: Write-Debug "my array is $($array|%{write-host $_; $_})"
How about:
BEGIN {
if ($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) {
$HasDebugFlag = $true
}
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
$HasVerboseFlag = $true
}
}
PROCESS {
if ($HasVerboseFlag) {
expensive_processing
}
}
Caveat: Tested only on PowerShell 3.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With