Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a cmdlet know when it really should call WriteVerbose()?

Tags:

powershell

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.

like image 672
Roman Kuzmin Avatar asked May 05 '10 17:05

Roman Kuzmin


2 Answers

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

like image 115
stej Avatar answered Sep 18 '22 07:09

stej


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.

like image 26
serialhobbyist Avatar answered Sep 22 '22 07:09

serialhobbyist