Как вы поддерживаете параметры PowerShell-WhatIf & - Confirm в Командлете, который вызывает другие командлеты?

у меня есть командлет сценария PowerShell, который поддерживает -WhatIf & -Confirm параметры.

он делает это, вызывая $PSCmdlet.ShouldProcess() метод перед выполнением изменения.
Это работает, как и ожидалось.

проблема в том, что мой командлет реализуется путем вызова других командлетов и -WhatIf или -Confirm параметры не передаются Командлетам, которые я вызываю.

как я могу передать значения -WhatIf и -Confirm в Командлеты мне позвонил мой командлет?

например, если мой командлет Stop-CompanyXyzServices и он использует Stop-Service реализовать свое действие.

если -WhatIf перешло к Stop-CompanyXyzServices Я хочу, чтобы он также был передан в Stop-Service.

возможно ли это?

4 ответов


передача параметров явно

вы можете пройти -WhatIf и -Confirm параметры $WhatIfPreference и $ConfirmPreference переменные. В следующем примере это достигается с помощью параметр splatting:

if($ConfirmPreference -eq 'Low') {$conf = @{Confirm = $true}}

StopService MyService -WhatIf:([bool]$WhatIfPreference.IsPresent) @conf

$WhatIfPreference.IsPresent будет True если -WhatIf переключатель используется на содержащей функции. С помощью -Confirm включение содержащей функции временно устанавливает $ConfirmPreference to low.

проходящий параметры неявно

С -Confirm и -WhatIf временно $ConfirmPreference и $WhatIfPreference переменные автоматически, даже необходимо передать их?

Рассмотрим пример:

function ShouldTestCallee {
    [cmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] 
    param($test)

    $PSCmdlet.ShouldProcess($env:COMPUTERNAME,"Confirm?")
}


function ShouldTestCaller {
    [cmdletBinding(SupportsShouldProcess=$true)]
    param($test)

    ShouldTestCallee
}

$ConfirmPreference = 'High'
ShouldTestCaller
ShouldTestCaller -Confirm

ShouldTestCaller результаты True С ShouldProcess()

ShouldTestCaller -Confirm результаты в запросе подтверждения, хотя я не прошел переключатель.

редактировать

@manojlds ответ заставил меня понять, что мой решение всегда сидел $ConfirmPreference "низкий" или "высокий". Я обновил свой код, чтобы установить только -Confirm переключатель, если параметр подтверждения "низкий".


после некоторых погуглив я придумал хорошее решение для передачи общих параметров вместе с названием команды. Вы можете использовать оператор @ splatting для передачи всех параметров, которые были переданы вашей команде. Например, если

Start-Service-Name ServiceAbc @PSBoundParameters

находится в теле скрипта powershell передаст все параметры, которые были переданы скрипту в команду Start-Service. Единственная проблема в том, что если ваш скрипт содержит параметр say a-Name, который также будет передан, и PowerShell будет жаловаться, что вы дважды включили параметр-Name. Я написал следующую функцию, чтобы скопировать все общие параметры в новый словарь, а затем я splat это.

function Select-BoundCommonParameters
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        $BoundParameters
    )
    begin
    {
        $boundCommonParameters = New-Object -TypeName 'System.Collections.Generic.Dictionary[string, [Object]]'
    }
    process
    {
        $BoundParameters.GetEnumerator() |
            Where-Object { $_.Key -match 'Debug|ErrorAction|ErrorVariable|WarningAction|WarningVariable|Verbose' } |
            ForEach-Object { $boundCommonParameters.Add($_.Key, $_.Value) }

        $boundCommonParameters
    }
}

конечный результат-вы передаете параметры, такие как-Verbose, командам, вызываемым в вашем скрипте, и они чтят намерение вызывающих.


вот полное решение, основанное на ответах @Rynant и @Shay Levy:

function Stop-CompanyXyzServices
{
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]

    Param(
        [Parameter(
            Position=0,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]      
        [string]$Name
    )

    process
    {
        if($PSCmdlet.ShouldProcess($env:COMPUTERNAME,"Stop XYZ services '$Name'")){  
            ActualCmdletProcess
        }
        if([bool]$WhatIfPreference.IsPresent){
            ActualCmdletProcess
        }
    }
}

function ActualCmdletProcess{
# add here the actual logic of your cmdlet, and any call to other cmdlets
Stop-Service $name -WhatIf:([bool]$WhatIfPreference.IsPresent) -Confirm:("Low","Medium" -contains $ConfirmPreference)
}

мы должны посмотреть, если -WhatIf передается отдельно, так что whatif может быть передан отдельным командлетам. ActualCmdletProcess в основном рефакторинг, так что вы не вызываете тот же набор команд снова только для WhatIf. Надеюсь, это кому-то поможет.


обновлено на комментарий @manojlds

Cast $WhatIf и $Confirm в Boolean и передают значения базовому командлету:

function Stop-CompanyXyzServices
{
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]

    Param(
        [Parameter(
            Position=0,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]      
        [string]$Name
    )


    process
    {
        if($PSCmdlet.ShouldProcess($env:COMPUTERNAME,"Stop service '$Name'"))
        {                   
            Stop-Service $name -WhatIf:([bool]$WhatIf) -Confirm:([bool]$confirm)
        }                       
    }
}