Powershell Cmdlet带有动态的' ConfirmImpact属性设置

时间:2016-05-27 16:56:34

标签: powershell cmdlets powershell-v5.0

我正在撰写支持ShouldProcess的Powershell cmdlet。我没有固定的ConfirmImpact价值,而是喜欢动态的'值取决于传递给cmdlet的参数的值。让我用一个例子来说明。

让我们假装我是一家网络托管服务提供商。我有很多网站,每个网站都属于以下类别之一,按重要性排序:ProductionTestDevelopment。作为托管管理的一部分,我有一个用于销毁网站的Remove-WebSite cmdlet。以下代码说明了这一点:

Class WebSite {
    [string] $Name
    [string] $Category # Can be one of: Production, Test, Development
}

Function Remove-WebSite {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true)]
        [WebSite] $WebSite
    )
    Write-Host "$($WebSite.Name) was destroyed"
}

目前,网站在未经确认的情况下销毁。虽然这很方便,但有太多的实习生错误地销毁了生产网站,所以我通过利用Powershell的ShouldProcess功能,在Remove-WebSite cmdlet上更喜欢安全网。

因此,我将SupportsShouldProcessConfirmImpact值添加到CmdletBinding属性中。我的cmdlet定义变为:

Function Remove-WebSite {
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]
    Param(
        [Parameter(Mandatory=$true)]
        [WebSite] $WebSite
    )

    if ($PSCmdlet.ShouldProcess("$($WebSite.Category) site $($WebSite.Name)")) {
        Write-Host "$($WebSite.Name) was destroyed"
    }
}

通过此定义,现在要求任何调用Remote-Website cmdlet的人确认他们确实要销毁该网站。现在几乎没有任何生产网站被破坏,除非网络开发者抱怨他们的自动脚本已停止工作。

我真正喜欢的是cmdlet的ConfirmImpact值在运行时会有所不同,具体取决于网站类别的重要性 - 生成网站的High,{{ 1}}用于测试站点,Medium用于开发站点。以下函数定义说明了这一点:

Low

假设可能,这怎么办?

这里粘贴了完整的脚本以及一些测试代码:http://pastebin.com/kuk6HNm6

2 个答案:

答案 0 :(得分:1)

这并不是你要求的(我认为严格来说,这是不可能的),但这可能是一种更好的方法。

单独ConfirmImpact而不是prompt the user with $PSCmdlet.ShouldContinue()

根据Requesting Confirmation from Cmdlets(强调我的)中给出的指导:

  

对于大多数cmdlet,您不必显式指定ConfirmImpact。而是使用参数的默认设置,即Medium。如果将ConfirmImpact设置为High,则默认情况下将确认操作。 为高度破坏性操作保留此设置,例如重新格式化硬盘卷。

此外:

  

大多数cmdlet仅使用ShouldProcess方法请求确认。但是,某些情况可能需要额外确认。对于这些情况,通过调用ShouldContinue方法补充ShouldProcess调用。

     

...

     

如果cmdlet调用ShouldContinue方法,则cmdlet还必须提供Force开关参数。如果用户在用户调用cmdlet时指定Force,则cmdlet仍应调用ShouldProcess,但它应绕过对ShouldContinue的调用。

鉴于此指导,我建议进行以下更改:

Function Remove-WebSite {
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
        [Parameter(Mandatory=$true)]
        [WebSite] $WebSite ,
        [Switch] $Force
    )

    if ($PSCmdlet.ShouldProcess("$($WebSite.Category) site $($WebSite.Name)")) {
        $destroy =
            $Force -or
            $WebSite.Category -ne 'Production' -or
            $PSCmdlet.ShouldContinue("Are you sure you want to destroy $($WebSite.Name)?", "Really destroy this?")
        if ($destroy) {
            Write-Host "$($WebSite.Name) was destroyed"
        }
    }
}

答案 1 :(得分:1)

最简单的解决方案是删除$PSCmdlet.ShouldProcess方法调用,并根据我们自己的标准有条件地调用$PSCmdlet.ShouldContinue方法。这个问题是我们失去了-WhatIf功能。正如briantist指出的那样,$PSCmdlet.ShouldContinue应该与$PSCmdlet.ShouldProcess一起使用,除非这会导致多余的确认提示,即当用户已经足够时,用户会提示两次。

通过实验,我发现通过在ConfirmImpact='None'属性声明中设置CmdletBindingShouldProcess不再显示提示,但仍会返回$false if {{ 1}}已指定。因此,-WhatIfShouldProcess都可以被调用,但仍然只向用户显示一个提示。然后我可以使用自己的逻辑来确定是否要调用ShouldContinue

这是一个完整的解决方案:

ShouldContinue