tags:

views:

47

answers:

1

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.

+2  A: 

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 $_; $_})"

stej
@stej: Thank you for your useful investigation. Theoretically it should be possible to hack in this way using reflection (because most of stuff is internal and not accessible normally). But of course this is not a practical solution. Nevertheless, I will accept the answer in a while if we do not find better alternatives.I also found a related suggestion at Connect:https://connect.microsoft.com/PowerShell/feedback/details/74811/performance-provide-formatting-overloads-for-writeverbose-writedebug-etc (This will not be enough though, I think; we need a flag IsVerbose, IsDebug, etc.)
Roman Kuzmin
@Roman, voted. | What currently came to my mind - when developing cmdlet, you should have access to all variables, shouldn't you. Then it is be possible to get `$DebugPrecedence` and act accordingly. Not ideal, but should work.
stej
@stej: `$DebugPreference`, `$VerbosePreference` are better than nothing, indeed. But they are not enough, because they are overridden by cmdlet ubiquitous parameters `-Verbose`, `-Debug` if any specified. But these parameters are not accessible from a cmdlet. Do parameters change the local `$DebugPreference`, `$VerbosePreference` implicitely? I doubt that, but I will try to find out.
Roman Kuzmin
“Do ubiquitous parameters change the local `$DebugPreference`, `$VerbosePreference`?” – No, they do not. Well, basically I am coming to a conclusion that in case of expensive verbose or debug output a cmdlet should introduce additional switches or even parameters, kind of `-VerboseLevel <int | string | enum>`. Hmm, perhaps this is not a bad idea, actually.
Roman Kuzmin
Yep, in some scripts I used exactly that. More levels of verbosity to get what I really want. And besides that.. I got rid off the 'VERBOSE:' and 'DEBUG:' prefixes.
stej