Как вы поддерживаете параметры 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)
}
}
}