8 Stimmen

Woher weiß ein Cmdlet, wann es WriteVerbose() wirklich aufrufen sollte?

Woher weiß ein Cmdlet, wann es wirklich sollte anrufen WriteVerbose() , WriteDebug() und usw.?

Vielleicht übersehe ich etwas Einfaches, aber ich kann die Antwort nicht finden. Alle Cmdlet Implementierungen, die ich bisher gesehen habe, rufen einfach WriteVerbose() ohne jegliche zögern. Ich weiß, dass es richtig dies zu tun, aber es ist nicht wirksam .

Die Leistung leidet, wenn der Ausführlichkeitsmodus ausgeschaltet ist, aber ein Cmdlet trotzdem vorbereitet wird Daten für WriteVerbose() Das heißt, umsonst.

Mit anderen Worten, in einem Cmdlet würde ich gerne in der Lage sein,:

if (<VerboseMode>)
{
    .... data preparation, sometimes expensive ...
    WriteVerbose(...);
}

Aber ich weiß nicht, wie ich das bekomme if (<VerboseMode>) . Irgendwelche Ideen?


Schlussfolgerung: Die Antwort von @stej zeigt, wie man die benötigten Informationen theoretisch erhält. In der Praxis ist dies hacky und unwahrscheinlich geeignet. Wenn ein Cmdlet also eine sehr umfangreiche ausführliche oder Debug-Ausgabe erzeugt, erscheint es sinnvoll, einen zusätzlichen Parameter einzuführen, der die Ausführlichkeitsstufen angibt.

7voto

stej Punkte 27477

Dies ist die Methode von 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 implementiert Schnittstelle ICommandRuntime die nichts über die Ausführlichkeit weiß :| (gefunden durch Reflektor). Instanz von MshCommandRuntime sollte verfügbar sein in Cmdlet ( public ICommandRuntime CommandRuntime { get; set; } ).

Es sollte also möglich sein, die Eigenschaft CommandRuntime a MshCommandRuntime und überprüfen Sie die Ausführlichkeit. Wie auch immer, das ist wirklich hässlich.


Ich stimme voll und ganz zu, dass es einen einfachen Weg geben sollte, um das herauszufinden. Und außerdem sollte der (träumende) Compiler klug genug sein, um einige Strings in solchen Fällen nicht auszuwerten:

$DebugPreference = 'SilentlyContinue'
$array = 1..1000
Write-Debug "my array is $array"

Eingabe in Write-Debug wird nie verwendet, daher $array sollte nicht in der übergebenen Zeichenkette ausgewertet werden (es ist möglich, zu testen, dass es wirklich so ausgewertet wird): Write-Debug "my array is $($array|%{write-host $_; $_})"

6voto

serialhobbyist Punkte 4730

Wie wäre es damit:

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

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

Vorbehalt: Nur mit PowerShell 3 getestet.

6voto

Lars Truijens Punkte 41774

Es müssen also nicht nur die gemeinsamen Parameter -Debug und -Verbose des Cmdlets berücksichtigt werden, sondern auch die globalen Flags $DebugPreference und $VerbosePreference sowie die Tatsache, dass diese gemeinsamen Parameter vererbt werden, wenn ein Cmdlet von einem anderen Cmdlet aufgerufen wird.

Es ist möglich, ohne in die Interna zu hacken.

Diese Antwort zeigt Ihnen, dass dies ohne große Probleme mit einem PowerShell-Cmdlet möglich ist.

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

In C# müssen wir diese beiden globalen Flags, aber auch die gemeinsamen Parameter überprüfen. Stellen Sie sicher, dass Sie von PSCmdlet statt von Cmdlet erben, um die GetVariableValue-Methode zu erreichen.

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;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X