当该函数没有Wha​​tIf参数时,禁止调用该函数/ cmdlet的WhatIf输出

时间:2019-05-25 04:16:03

标签: powershell

TL; DR -当函数/ cmdlet没有-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$'

通过在 my 函数调用上指定-WhatIf,它已在我的函数调用的函数上传递了该首选项。这是设计使然,在大多数情况下是您想要的。

出于完整性考虑,Test-ADServiceAccount应该返回$true$false,具体取决于是否已在本地计算机上安装了特定的托管服务(至少,如果您取消了对它的管理,则可以这样做)。警告/错误)。

但是,在这种情况下,由于似乎写了Test-ADServiceAccount的方式,如果在 my 函数调用中提供了-WhatIf,它实际上不会执行测试,因此始终返回$false。这意味着我的if / else逻辑被破坏了-我的函数应该 not 表示如果{{ 1}}已删除。

在通常情况下,我只会在被调用函数的末尾添加Install-ADServiceAccount,但是registered$不会公开其自己的-WhatIf参数:

-WhatIf:$false

我很欣赏可能有更好的方法来编写该函数,并且这里实际上并没有造成任何危害,因为无论如何Test-ADServiceAccount都没有运行,但是此函数旨在用作MCVE,而不是为了明确改进。我也很感激-WhatIf可能不需要PS> Test-ADServiceAccount -WhatIf:$false -Identity 'registered$' Test-ADServiceAccount : A parameter cannot be found that matches parameter name 'WhatIf'. 的语义,也许自己不应该自己做Install-ADServiceAccount(我认为是这样做的),但是Test-ADServiceAccount不是我的模块而且我看不到我会很快改变其行为。

在一般情况下,当 my <时,如何从我自己的函数中覆盖我无法控制的调用cmdlet /函数的-WhatIf行为/ em>函数使用其$PSCmdlet.ShouldProcess参数进行调用,而调用函数不会公开其自身的ActiveDirectory参数。

1 个答案:

答案 0 :(得分:1)

您可以在致电$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"
        }
    }

在此stackoverflow answer中找到了$WhatIfPreference.IsPresent

似乎Test-AdServiceAccount以动态方式检测到WhatIf开关,例如通过$WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference')

更新

基于@Jessens注释,您还可以将特定功能包装在脚本块中并调用invoke-command { $WhatIfPreference = $false; Function2;},在这里您无需重建旧的$WhatIfPreference状态。

希望有帮助。