【问题标题】:How to Use -confirm in PowerShell如何在 PowerShell 中使用 -confirm
【发布时间】:2014-08-30 04:53:25
【问题描述】:

我正在尝试接受用户输入,在继续之前,我希望在屏幕上收到一条消息,而不是确认用户是否要继续。我正在使用以下代码,但它不起作用:

write-host "Are you Sure You Want To Proceed:"  -Confirm

【问题讨论】:

    标签: powershell


    【解决方案1】:

    -Confirm 是大多数 PowerShell cmdlet 中的一个开关,它强制 cmdlet 要求用户确认。你真正要找的是Read-Host cmdlet:

    $confirmation = Read-Host "Are you Sure You Want To Proceed:"
    if ($confirmation -eq 'y') {
        # proceed
    }
    

    或主机用户界面的PromptForChoice()方法:

    $title    = 'something'
    $question = 'Are you sure you want to proceed?'
    
    $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No'))
    
    $decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
    if ($decision -eq 0) {
        Write-Host 'confirmed'
    } else {
        Write-Host 'cancelled'
    }
    

    编辑:

    正如 M-pixel 在 cmets 中指出的那样,代码可以进一步简化,因为选择可以作为简单的字符串数组传递。

    $title    = 'something'
    $question = 'Are you sure you want to proceed?'
    $choices  = '&Yes', '&No'
    
    $decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
    if ($decision -eq 0) {
        Write-Host 'confirmed'
    } else {
        Write-Host 'cancelled'
    }
    

    【讨论】:

    • 它可以在没有显式类型和对象声明的情况下工作:$decision = $Host.UI.PromptForChoice('something', 'Are you sure you want to proceed?', @('&Yes'; '&No'), 1)
    • 仅供参考,在丰富的环境(如 PowerShell ISE)中,$message 是弹出窗口的标题。因此,您确实需要保持简短,并将整个消息(包括问题)放入$question 变量中。 ($message 真的应该重命名为$title)。
    • 嗯,我在 Exchange 命令行管理程序上运行的 PS 4.0 上得到了这个,可能必须使用完整的显式对象声明:无法转换参数“选择”,值为:“System.Object []” ,对于“PromptForChoice”,键入“System.Collections.ObjectModel.Collection`1[System.Management.Automation.Host.ChoiceDescription]”
    【解决方案2】:

    这是一个简单的循环,除非用户选择'y'或'n',否则会一直提示

    $confirmation = Read-Host "Ready? [y/n]"
    while($confirmation -ne "y")
    {
        if ($confirmation -eq 'n') {exit}
        $confirmation = Read-Host "Ready? [y/n]"
    }
    

    【讨论】:

    • break 将正确退出 while 循环,而不是 exit!它确实取决于上下文:break vs exit vs return@dallyack
    • 不要使用read-host进行确认,也不要使用exitbreak
    • 这太完美了!我绝对想exit 而不是break
    • 使用 doo...while 循环,您无需重复 Read-Host 行:do { $yn = Read-Host "Ready? [y/n]"; if ($yn-eq 'n') {exit}; } while($yn -ne "y")
    【解决方案3】:

    Read-Host-Confirm 对它没有影响的 cmdlet 的一个示例。-Confirm 是 PowerShell 的常用参数之一,特别是在 cmdlet 即将进行更改时使用的风险缓解参数到 Windows PowerShell 环境之外的系统。许多但不是所有 cmdlet 都支持 -Confirm 风险缓解参数。

    以下是使用Read-Host cmdlet 和正则表达式测试来获得用户确认的示例:

    $reply = Read-Host -Prompt "Continue?[y/n]"
    if ( $reply -match "[yY]" ) { 
        # Highway to the danger zone 
    }
    

    Remove-Variable cmdlet 是一个说明-confirm 开关用法的示例。

    Remove-Variable 'reply' -Confirm
    

    其他参考:CommonParametersWrite-HostRead-HostComparison OperatorsRegular ExpressionsRemove-Variable

    【讨论】:

    • 不需要带出正则表达式。 -eq 不区分大小写。 $reply -eq 'y' 就足够了。
    【解决方案4】:

    write-host 没有-confirm 参数。

    你可以这样做:

        $caption = "Please Confirm"    
        $message = "Are you Sure You Want To Proceed:"
        [int]$defaultChoice = 0
        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Do the job."
        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Do not do the job."
        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
        $choiceRTN = $host.ui.PromptForChoice($caption,$message, $options,$defaultChoice)
    
    if ( $choiceRTN -ne 1 )
    {
       "Your Choice was Yes"
    }
    else
    {
       "Your Choice was NO"
    }
    

    【讨论】:

    • 我认为这样更好,因为会有 3 个选项。最后一个会有所帮助,您可以在此处添加更清晰的解释,“是”和“否”实际上在做什么。
    【解决方案5】:

    这里是来自 Microsoft 的 documentation,关于如何在 cmdlet 中请求确认。这些示例使用 C# 编写,但您也可以执行 PowerShell 中显示的所有操作。

    首先将CmdletBinding 属性添加到您的函数中,并将SupportsShouldProcess 设置为true。然后可以引用$PSCmdlet变量的ShouldProcessShouldContinue方法。

    这是一个例子:

    function Start-Work {
        <#
        .SYNOPSIS Does some work
        .PARAMETER Force
            Perform the operation without prompting for confirmation
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            # This switch allows the user to override the prompt for confirmation
            [switch]$Force
        )
        begin { }
        process {
            if ($PSCmdlet.ShouldProcess('Target')) {
                if (-not ($Force -or $PSCmdlet.ShouldContinue('Do you want to continue?', 'Caption'))) {
                    return # user replied no
                }
    
                # Do work
            }
    
        }
        end { }
    }
    

    【讨论】:

    • 我认为注释 # Do work 的位置缺少右括号 (})。
    • 很确定这只是markdown中的奇怪格式,您是否尝试将代码粘贴到IDE中查看是否有任何编译器错误?
    • 不,我刚刚看到您的 ShouldProcess 条件没有右括号,但也许这是一种奇怪的格式,这就是我说我认为的原因
    • 我修复了格式问题,使大括号对齐。
    【解决方案6】:

    当你想要一个 1-liner

    while( -not ( ($choice= (Read-Host "May I continue?")) -match "y|n")){ "Y or N ?"}
    

    【讨论】:

    • @BrainSlugs83 您使用读取主机不厌其烦地评论/否决大多数答案?您是否也会更新 PowerShell 文档,更不用说,The Read-Host cmdlet reads a line of input from the console. You can use it to prompt a user for input? -- docs.microsoft.com/en-us/powershell/module/…
    【解决方案7】:
    Write-Warning "This is only a test warning." -WarningAction Inquire
    

    来自: https://serverfault.com/a/1015583/584478

    【讨论】:

      【解决方案8】:

      这是我使用过的解决方案,类似于 Ansgar Wiechers 的解决方案;

      $title = "Lorem"
      $message = "Ipsum"
      
      $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "This means Yes"
      $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "This means No"
      
      $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
      
      $result = $host.ui.PromptForChoice($title, $message, $Options, 0)
      
      Switch ($result)
           {
                0 { "You just said Yes" }
                1 { "You just said No" }
           }
      

      【讨论】:

      • 如果他们关闭对话框,$result 不会是 0 或 1。
      【解决方案9】:

      基于Ansgar Wiechers's answer 的稍微漂亮的函数。它是否真的更有用是一个争论的问题。

      function Read-Choice(
         [Parameter(Mandatory)][string]$Message,
         [Parameter(Mandatory)][string[]]$Choices,
         [Parameter(Mandatory)][string]$DefaultChoice,
         [Parameter()][string]$Question='Are you sure you want to proceed?'
      ) {
          $defaultIndex = $Choices.IndexOf($DefaultChoice)
          if ($defaultIndex -lt 0) {
              throw "$DefaultChoice not found in choices"
          }
      
          $choiceObj = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
      
          foreach($c in $Choices) {
              $choiceObj.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList $c))
          }
      
          $decision = $Host.UI.PromptForChoice($Message, $Question, $choiceObj, $defaultIndex)
          return $Choices[$decision]
      }
      

      示例用法:

      PS> $r = Read-Choice 'DANGER!!!!!!' '&apple','&blah','&car' '&blah'
      
      DANGER!!!!!!
      Are you sure you want to proceed?
      [A] apple  [B] blah  [C] car  [?] Help (default is "B"): c
      PS> switch($r) { '&car' { Write-host 'caaaaars!!!!' } '&blah' { Write-Host "It's a blah day" } '&apple' { Write-Host "I'd like to eat some apples!" } }
      caaaaars!!!!
      

      【讨论】:

        【解决方案10】:

        我更喜欢弹出窗口。

        $shell = new-object -comobject "WScript.Shell"
        $choice = $shell.popup("Insert question here",0,"Popup window title",4+32)
        

        如果 $choice 等于 6,答案是肯定的 如果 $choice 等于 7,则答案是否定的

        【讨论】:

        • 这有一个主要缺点,它不能适应您正在使用的主机。因此,例如,如果您要远程连接到服务器,则最好的情况是失败,最坏的情况是冻结脚本。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-10
        • 2021-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-21
        • 2011-11-03
        相关资源
        最近更新 更多