PowerShell 中是否有用于交互式提示的模块或类似的东西?

Is there a Module or Something Similar for Interactive Prompts in PowerShell?

我们可以在 PowerShell 中使用某些东西来要求用户 select 一组项目中的一个项目吗?例如,我喜欢 Inquirer.js 的做法。

我也看到了PoshGui,但是只创建一个简单的提示似乎工作量太大了。

我们想要类似的东西的原因是我们需要为我们的客户提供部署脚本并使部署指南尽可能简单。要求用户 select 屏幕上的一项比要求他们将一些 guid 插入配置文件要好得多。

您对数组的用户提示有什么建议吗?

我过去为此使用过 Out-GridView cmdlet。当与 -PassThru 开关一起使用时,它允许将所选项目传递给变量。您显示的示例图像在使用 Out-GridView 编写时(ogv 如果您想使用别名)是:

$task = Read-Host -Prompt "What do you want to do?"

if ($task -eq "Order a pizza") {
  $pizza_sizes = @('Jumbo','Large','Standard','Medium','Small','Micro')
  $size = $pizza_sizes | Out-GridView -Title "What size do you need?"  -PassThru
  Write-Host "You have selected $size"
}

这需要考虑很多因素,windows 可能不会出现在您希望它们出现的位置,它们可能会出现在其他人的后面。此外,这是一个非常简单的示例,显然需要内置的错误处理和其他方面。我建议进行一些测试或从其他人那里获得关于 SO 的第二意见。

你当然可以随心所欲地发挥创意.. 这是一个构建控制台菜单的小函数:

function Simple-Menu {
    Param(
        [Parameter(Position=0, Mandatory=$True)]
        [string[]]$MenuItems,
        [string] $Title
    )

    $header = $null
    if (![string]::IsNullOrWhiteSpace($Title)) {
        $len = [math]::Max(($MenuItems | Measure-Object -Maximum -Property Length).Maximum, $Title.Length)
        $header = '{0}{1}{2}' -f $Title, [Environment]::NewLine, ('-' * $len)
    }

    # possible choices: didits 1 to 9, characters A to Z
    $choices = (49..57) + (65..90) | ForEach-Object { [char]$_ }
    $i = 0
    $items = ($MenuItems | ForEach-Object { '[{0}]  {1}' -f $choices[$i++], $_ }) -join [Environment]::NewLine

    # display the menu and return the chosen option
    while ($true) {
        cls
        if ($header) { Write-Host $header -ForegroundColor Yellow }
        Write-Host $items
        Write-Host

        $answer = (Read-Host -Prompt 'Please make your choice').ToUpper()
        $index  = $choices.IndexOf($answer[0])

        if ($index -ge 0 -and $index -lt $MenuItems.Count) {
            return $MenuItems[$index]
        }
        else {
            Write-Warning "Invalid choice.. Please try again."
            Start-Sleep -Seconds 2
        }
    }
}

您可以像下面这样使用它:

$menu = 'Pizza', 'Steak', 'French Fries', 'Quit'
$eatThis = Simple-Menu -MenuItems $menu -Title "What would you like to eat?"
switch ($eatThis) {
    'Pizza' {
        $menu = 'Jumbo', 'Large', 'Standard', 'Medium', 'Small', 'Micro'
        $eatThat = Simple-Menu -MenuItems $menu -Title "What size do you need?"
        Write-Host "`r`nEnjoy your $eatThat $eatThis!`r`n" -ForegroundColor Green
    }
    'Steak' {
        $menu = 'Well-done', 'Medium', 'Rare', 'Bloody', 'Raw'
        $eatThat = Simple-Menu -MenuItems $menu -Title "How would you like it cooked?"
        Write-Host "`r`nEnjoy your $eatThat $eatThis!`r`n" -ForegroundColor Green
    }
    'French fries' {
        $menu = 'Mayonaise', 'Ketchup', 'Satay Sauce', 'Piccalilly'
        $eatThat = Simple-Menu -MenuItems $menu -Title "What would you like on top?"
        Write-Host "`r`nEnjoy your $eatThis with $eatThat!`r`n" -ForegroundColor Green
    }
}

结果:

不幸的是,内置的东西很少,而且很难发现 - 见下文。

可能提供专用 Read-Choice cmdlet 或增强 Read-Host is being discussed on GitHub.

$host.ui.PromptForChoice() 方法支持显示选项菜单,但有局限性:

  • 选项显示在单行(可能会换行)。

  • 仅支持单字符选择器。

  • 选择符必须是菜单项文本的一部分。

  • 提交选择总是需要按 Enter

  • 总是会提供一个 ? 选项,即使您不想/不需要为每个菜单项提供解释性文本。

这是一个例子:

# The list of choices to present.
# Specfiying a selector char. explicitly is mandatory; preceded it by '&'.
# Automating that process while avoiding duplicates requires significantly
# more effort.
# If you wanted to include an explanation for each item, selectable with "?",
# you'd have to create each choice with something like:
#   [System.Management.Automation.Host.ChoiceDescription]::new("&Jumbo", "16`" pie")
$choices = '&Jumbo', '&Large', '&Standard', '&Medium', 'Sma&ll', 'M&icro'

# Prompt the user, who must type a selector character and press ENTER.
# * Each choice label is preceded by its selector enclosed in [...]; e.g.,
#   '&Jumbo' -> '[J] Jumbo'
# * The last argument - 0 here - specifies the default index.
#   * The default choice selector is printed in *yellow*.
#   * Use -1 to indicate that no default should be provided
#     (preventing empty/blank input).
# * An invalid choice typed by the user causes the prompt to be 
#   redisplayed (without a warning or error message).
$index = $host.ui.PromptForChoice("Choose a Size", "Type an index and press ENTER:", $choices, 0)

"You chose: $($choices[$index] -replace '&')"

这会产生如下内容:

所有的答案都是正确的,但我也写了一些可重复使用的PowerShell helper functions. Readme。我 auto-generate 基本的 WinForms。看起来丑陋,但有效。

https://github.com/Zerg00s/powershell-forms

$selectedItem = Get-FormArrayItem (Get-ChildItem)

$Delete = Get-FormBinaryAnswer "Delete file?"

$newFileName = Get-FormStringInput "Enter new file name" -defaultValue "My new file"

# -------------------------------------------------------------------------------
# Prepare the list of inputs that user needs to populate using an interactive form    
# -------------------------------------------------------------------------------
$preDeployInputs = @{
    suffix                       = ""
    SPSiteUrl                    = "https://ENTER_SHAREPOINT_SITE.sharepoint.com"
    TimeZone                     = "Central Standard Time"
    sendGridRegistrationEmail    = "ENTER_VALID_EMAIL_ADDRESS"
    sendGridRegistrationPassword = $sendGridPassword
    sendGridRegistrationCompany  = "Contoso & Tailspin"
    sendGridRegistrationWebsite  = "https://www.company.com"
    fromEmail                    = "no-reply@DOMAIN.COM"
}

$preDeployInputs = Get-FormItemProperties -item $preDeployInputs -dialogTitle "Fill these required fields"

您也可以尝试 ps-menu 模块: https://www.powershellgallery.com/packages/ps-menu

样本: