Как командлет узнает, когда он действительно должен вызывать WriteVerbose ()? - PullRequest
6 голосов
/ 05 мая 2010

Как командлет узнает, когда действительно должен вызвать WriteVerbose(), WriteDebug() и др .?

Возможно, я упускаю что-то простое, но не могу найти ответ. Все командлеты реализации, которые я видел до сих пор, просто позвоните WriteVerbose() без каких-либо нерешительность. Я знаю, что это правильно , но это не эффективно .

Производительность снижается, когда подробный режим отключен, но командлет все еще готовится данные для WriteVerbose() звонка, то есть даром.

Другими словами, в командлете я хотел бы иметь возможность:

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

Но я не знаю, как получить это if (<VerboseMode>). Есть идеи?


Вывод: Ответ @ stej показывает, как получить необходимую информацию в теории. На практике это неприлично и вряд ли подходит. Таким образом, если командлет выдает действительно дорогой подробный или отладочный вывод, то разумно ввести дополнительный параметр, определяющий уровни многословия.

Ответы [ 3 ]

6 голосов
/ 06 мая 2010

Это метод из 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"

Ввод в Write-Debug никогда не будет использоваться, поэтому $array не следует оценивать в переданной строке .. (можно проверить, что оно действительно оценивается так: Write-Debug "my array is $($array|%{write-host $_; $_})"

5 голосов
/ 29 декабря 2013

Таким образом, мы должны учитывать не только общие параметры -Debug и -Verbose командлета, но и глобальные флаги $ DebugPreference и $ VerbosePreference и тот факт, что эти общие параметры наследуются, если командлет вызывается из другой командлет.

Это можно сделать без взлома внутренних органов.

Этот ответ показывает, что это можно сделать с небольшими проблемами в командлете PowerShell.

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; 
4 голосов
/ 23 июля 2013

Как насчет:

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

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

Предупреждение: протестировано только на PowerShell 3.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...