servicio - ¿Cómo admite los parámetros-WhatIf y-Confirmación de PowerShell en un cmdlet que llama a otros cmdlets?
servicio de powershell (4)
Aquí hay una solución completa basada en las respuestas de @Rynant y @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)
}
Tenemos que ver si -WhatIf
se pasa por separado para que el whatif se pueda transmitir a los cmdlets individuales. ActualCmdletProcess
es básicamente una refactorización para que no vuelva a llamar el mismo conjunto de comandos solo para el WhatIf
. Espero que esto ayude a alguien.
Tengo un cmdlet de script de PowerShell que admite los parámetros -WhatIf
& -Confirm
.
Lo hace llamando al $PSCmdlet.ShouldProcess()
antes de realizar el cambio.
Esto funciona como se esperaba.
El problema que tengo es que mi Cmdlet se implementa llamando a otros Cmdlets y los parámetros -WhatIf
o -Confirm
no se pasan a los Cmdlets que invoco.
¿Cómo puedo pasar los valores de -WhatIf
y -Confirm
a los Cmdlets que llamo desde mi Cmdlet?
Por ejemplo, si mi Cmdlet es Stop-CompanyXyzServices
y usa Stop-Service
para implementar su acción.
Si -WhatIf
se pasa a Stop-CompanyXyzServices
, quiero que también se pase a Stop-Service.
es posible?
Después de buscar en Google, encontré una buena solución para pasar parámetros comunes a los comandos llamados. Puede utilizar el operador @ splatting para pasar todos los parámetros que se pasaron a su comando. Por ejemplo, si
Servicio de inicio -Nombre ServiceAbc @PSBoundParameters
está en el cuerpo de su script. powershell pasará todos los parámetros que se pasaron a su script al comando Iniciar-Servicio. El único problema es que si la secuencia de comandos contiene un parámetro -Nombre, también se pasará y PowerShell se quejará de que incluyó el parámetro -Nombre dos veces. Escribí la siguiente función para copiar todos los parámetros comunes a un nuevo diccionario y luego lo escribí.
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
}
}
El resultado final es que pasa parámetros como -Verbose junto con los comandos llamados en su script y respetan la intención de las personas que llaman.
Actualizado por @manojlds comentario
Convierta $ WhatIf y $ Confirm a Boolean y pase los valores al cmdlet subyacente:
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)
}
}
}
Pasando parámetros explícitamente
Puede pasar los parámetros -WhatIf
y -Confirm
con las $WhatIfPreference
y $ConfirmPreference
. El siguiente ejemplo logra esto con el parámetro splatting :
if($ConfirmPreference -eq ''Low'') {$conf = @{Confirm = $true}}
StopService MyService -WhatIf:([bool]$WhatIfPreference.IsPresent) @conf
$WhatIfPreference.IsPresent
será True
si se usa el interruptor -WhatIf
en la función que lo contiene. Al usar el interruptor -Confirm
en la función que contiene, se establece temporalmente $ConfirmPreference
a low
.
Pasando parámetros implícitamente
Dado que las -Confirm
y -WhatIf
establecen temporalmente las variables $ConfirmPreference
y $WhatIfPreference
automática, ¿es incluso necesario pasarlas?
Considera el ejemplo:
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
da ShouldTestCaller
resultado True
desde ShouldProcess()
ShouldTestCaller -Confirm
resulta en un mensaje de confirmación a pesar de que no pasé el interruptor.
Editar
La respuesta de @manojlds me hizo darme cuenta de que mi solución siempre estaba configurando $ConfirmPreference
en ''Bajo'' o ''Alto''. He actualizado mi código para establecer solo el interruptor -Confirm
si la preferencia de confirmación es ''Baja''.