Подавление вывода WhatIf вызываемой функции / командлета, когда эта функция не имеет параметра WhatIf - PullRequest
3 голосов
/ 25 мая 2019

TL; DR - Как указать -WhatIf:$false, если функция / командлет не имеет параметра -WhatIf, но все еще реагирует на -WhatIf в родительском вызове?

Рассмотрим следующий слегка надуманный пример:

Import-Module ActiveDirectory

Function Test-MyFunction {
    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
    Param(
        [Parameter(Mandatory=$true)]
        [String] $Identity
    )

    $private:q = ($Identity -replace "'","''")
    if (Get-ADServiceAccount -Filter "sAMAccountName -eq '${private:q}'") {
        if (-not (Test-ADServiceAccount -Identity $Identity `
                                        -WarningAction 'SilentlyContinue' `
                                        -ErrorAction 'SilentlyContinue'))
        {
            if ($PSCmdlet.ShouldProcess($Identity, 'Install')) {
                Install-ADServiceAccount -Identity $Identity
            }
            else {
                Write-Verbose "Skipped processing '$Identity'"
            }
        }
        else {
            Write-Verbose "Already registered '$Identity'"
        }
    }
    else {
        Write-Warning "'$Identity' does not exist"
    }
}

... и его возможные выводы:

PS> Test-MyFunction -Verbose -Identity 'nonexistent$'
WARNING: 'nonexistent$' does not exist

PS> Test-MyFunction -Verbose -Identity 'registered$'
VERBOSE: Already registered 'registered$'

PS> Test-MyFunction -Verbose -Identity 'notregistered$'
Confirm
Are you sure you want to perform this action?
Performing the operation "Install" on target "notregistered$"
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): n
VERBOSE: Skipped processing 'notregistered$'

Если я добавлю -WhatIf к этим вызовам, вы получитеследующее:

PS> Test-MyFunction -WhatIf -Verbose -Identity 'nonexistent$'
WARNING: 'nonexistent$' does not exist

PS> Test-MyFunction -WhatIf -Verbose -Identity 'registered$'
What if: Performing the operation "Test" on target "CN=registered,CN=Managed Service Accounts,DC=contoso,DC=local"
What if: Performing the operation "Install" on target "registered$"
VERBOSE: Skipped processing 'registered$'

PS> Test-MyFunction -WhatIf -Verbose -Identity 'notregistered$'
What if: Performing the operation "Test" on target "CN=notregistered,CN=Managed Service Accounts,DC=contoso,DC=local"
What if: Performing the operation "Install" on target "notregistered$"
VERBOSE: Skipped processing 'notregistered$'

Указав -WhatIf на my вызове функции, он передал это предпочтение функциям, вызываемым моей функцией.Это задуманно и, в большинстве случаев, вам нужно.

Для полноты Test-ADServiceAccount должен возвращать $true или $false в зависимости от того, установлена ​​ли конкретная управляемая служба налокальный компьютер (по крайней мере, это происходит, если вы подавляете его предупреждения / ошибки).

Однако, в этом случае, из-за способа, которым, как представляется, написано Test-ADServiceAccount, если -WhatIf указано на вызов функции , фактически он никогда не выполняет тест, поэтому всегда возвращает $false.Это означает, что моя if / else логика не работает - моя функция должна , а не указывать, что Install-ADServiceAccount будет вызываться для registered$, если -WhatIf было удалено.

В обычных условиях я бы просто добавил -WhatIf:$false в конец вызываемой функции, но Test-ADServiceAccount не предоставляет свой собственный параметр -WhatIf:

PS> Test-ADServiceAccount -WhatIf:$false -Identity 'registered$'
Test-ADServiceAccount : A parameter cannot be found that matches parameter name 'WhatIf'.

Я понимаю, что, вероятно, естьлучшие способы написания функции и то, что здесь действительно нет никакого вреда, потому что Install-ADServiceAccount все равно не запускался, но эта функция была задумана как MCVE, а не как нечто, что было бы явно улучшено.Я также ценю, что Test-ADServiceAccount может не потребоваться -WhatIf семантика и, вероятно, сама не должна делать $PSCmdlet.ShouldProcess (что я предполагаю, что это делает), но ActiveDirectory не мой модуль, и я не вижу, как я меняюсьего поведение в ближайшее время.

В общем случае , как я могу переопределить поведение -WhatIf для вызываемого командлета / функции, которой я не управляю, изнутри моей собственной функции,когда функция my вызывается с ее параметром -WhatIf, а функция вызываемая не предоставляет свой собственный параметр -WhatIf.

1 Ответ

1 голос
/ 25 мая 2019

Вы можете установить $WhatIfPreference на $false перед вызовом Test-AdServiceAccount. После этого вы можете восстановить предпочтение

    function Function1 {
        [CmdletBinding(SupportsShouldProcess = $true)]
        param (
        )

        $origWhatIfPreference = $WhatIfPreference.IsPresent

        $WhatIfPreference = $false
        Function2
        $WhatIfPreference = $origWhatIfPreference

        if ($PSCmdlet.ShouldProcess("target", "command")) {
            Write-Host "test"
        }
    }

    function Function2 {
        [CmdletBinding(SupportsShouldProcess = $true)]
        param (
        )
        if ($PSCmdlet.ShouldProcess("f2: target", "f2: command")) {
            Write-Host "f2: test"
        }
    }

Найден $WhatIfPreference.IsPresent в этом stackoverflow ответе .

Кажется, что Test-AdServiceAccount обнаруживает переключатель WhatIf динамически, например, через $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference')

Обновление:

На основе комментария @Jessens вы также можете обернуть определенную функцию в блок скрипта и вызвать ее invoke-command { $WhatIfPreference = $false; Function2;}, здесь вам не нужно будет восстанавливать старое состояние $WhatIfPreference.

Надеюсь, это поможет.

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