Поддержка ответов Whatif и Confirm

Здесь, в SO, и в других местах есть множество вопросов, объясняющих, как распространить -Confirm по всему командлету на вложенные командлеты и т. д. Однако я не нахожу, как распространить ответ на это приглашение. То есть, как только пользователь ответит на это приглашение...

[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):

... можно разумно предположить, что мой командлет теперь может воздействовать на ответ пользователя на это приглашение. Отчасти это, безусловно, верно: и Suspend [S], и Help [?] являются локализованными операциями, и они работают нормально.

Но моя главная проблема заключается в распознавании и воздействии на Yes to All и No to All. Как в C# (через Cmdlet.ShouldProcess()), так и в PowerShell (через $PSCmdlet.ShouldProcess()) можно получить только логический результат, о котором я могу только догадываться:

  • true это либо [Y], либо [A].
  • false это либо [N], либо [L].

Сначала я надеялся, что ShouldContinue, хотя и не задокументировано как таковое, будет использовать внутреннее состояние командлета, чтобы сделать это различие, но эксперименты со сценариями командлетов показали, что это не так.

На самом деле, единственный возможный обходной путь, который я нашел до сих пор, это Ранняя интерпретация Джеффри Сновером (около 2007 г.!) функции Should-Process для PowerShell, предположительно до появления "официальных" Cmdlet.ShouldProcess и $PSCmdlet.ShouldProcess.

Мне трудно поверить, что команда PowerShell забыла разрешить различать Да/Да для всех и Нет/Нет для всех; скорее я предполагаю, что я просто пропускаю это.

Итак, мой вопрос в краткой форме: как для скомпилированных командлетов, так и для командлетов со сценариями, как я могу отличить Yes от Yes to All и No от No to All ?


person Michael Sorens    schedule 12.04.2014    source источник


Ответы (1)


Я считаю, что опция Yes to all означает сказать «Да, выполнить эту операцию для всех элементов, над которыми я сейчас работаю», а не «Да, выполнить все возможные операции и больше не спрашивать меня». Один из способов проверить это — направить массив в функцию, которая поддерживает ShouldProcess, которая внутренне вызывает внутреннюю функцию (которая также поддерживает ShouldProcess) с одним элементом за раз. Вы увидите, что, по крайней мере, в PowerShell v4.0 на моей машине с Win 8.1 внешняя функция, в которую я передал массив, не запрашивает другие элементы в массиве. Однако внутренняя функция, которая вызывается много раз, в отличие от однократного вызова с массивом для ввода, будет запрашивать один раз при каждом вызове.

Мы можем проверить это поведение, используя следующую функцию и внутреннюю функцию:

function Test-ShouldProcess
{
    [CmdletBinding(SupportsShouldProcess = $true)]
    PARAM (
        [Parameter(ValueFromPipeline = $true)]
        $InputObject
    )

    PROCESS
    {
        if ($PSCmdlet.ShouldProcess($InputObject, "Do stuff to it"))
        {
            Write-Host "Doing stuff to $InputObject"
            Test-ShouldProcess_InnerFunc -InputObject $InputObject
        }
    }
}

function Test-ShouldProcess_InnerFunc
{
    [CmdletBinding(SupportsShouldProcess = $true)]
    PARAM (
        [Parameter(ValueFromPipeline = $true)]
        $InputObject
    )

    PROCESS
    {
        if ($PSCmdlet.ShouldProcess($InputObject, "Do internal stuff to it"))
        {
            Write-Host "Doing internal stuff to $InputObject"
        }
    }
}

Если мы вызовем внешнюю функцию, передав ей массив, например:

"item1", "item2" | Test-ShouldProcess -Confirm

Учитывая, что мы отвечаем «Да всем» на каждое приглашение, мы получим следующий вывод:

Confirm
Are you sure you want to perform this action?
Performing the operation "Do stuff to it" on target "item1".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): A
Doing stuff to item1

Confirm
Are you sure you want to perform this action?
Performing the operation "Do internal stuff to it" on target "item1".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): A
Doing internal stuff to item1
Doing stuff to item2

Confirm
Are you sure you want to perform this action?
Performing the operation "Do internal stuff to it" on target "item2".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): A
Doing internal stuff to item2

Обратите внимание, что он запрашивает один раз «Сделать с ним что-то», а затем один раз «Сделать с ним внутреннее действие». Следующая строка, сразу после выполнения внутренней функции, является выходом внешней функции для второго элемента в массиве, _без подсказки, так как мы ответили «Да для всех». Внешняя функция для второго элемента снова вызывает внутреннюю функцию как вызов одного элемента, и поэтому PowerShell снова запрашивает пользователя.

Причина повторного запроса PowerShell заключается в том, что это новые инструкции, работающие с новым набором данных. Так что, пока одна и та же инструкция работает со списком данных, «Да для всех» не будет снова запрашивать более поздние элементы в списке, а будет запрашивать новые инструкции или новые наборы данных. снова спросите.

Если пользователь вообще не хочет запрашивать подтверждение, ему не следует использовать переключатель -Confirm и, возможно, даже изменять настройку ConfirmPreference или, возможно, использовать переключатель -Force.

person Robert Westerlund    schedule 13.04.2014
comment
Моя реакция на ваш ответ: спасибо! Роберт, вы даете полезную информацию о том, что все функциональные возможности являются автономными и не требуется дополнительный вывод, основанный на реализации механизма. Но моя реакция на содержание вашего ответа такова: Вааа! Это плохой пользовательский интерфейс. По сути, вы говорите, что PowerShell дает подсказки, которые писатель кода поймет/оценит, но это не очень полезно для пользователь кода. - person Michael Sorens; 15.04.2014
comment
У писателя кода есть возможность написать код таким образом, чтобы пользователь не получил этого опыта, работая с операциями на основе наборов. Я не уверен, как PowerShell должен был справиться с этим по-другому. Единственный другой вариант, который я вижу, это то, что Yes to all будет означать don't ask me for anything again, что лично мне не нравится. Я считаю don't ask me for again for this set of data хорошей реализацией. Кроме того, если пользователь вообще не хочет, чтобы его запрашивали, ему не следует добавлять переключатель -Confirm. - person Robert Westerlund; 15.04.2014