【问题标题】:How to make a variable a range in PowerShell?如何在PowerShell中使变量成为范围?
【发布时间】:2019-06-15 05:29:03
【问题描述】:

我正在尝试使变量等于一个范围。 我的脚本包含用户输入,并且此输入必须在一定范围内。我将在脚本中使用该范围几次,所以我希望它是一个变量。 这是我尝试过的:

    $serverrange = "1..18"

我试过了

    $serverrange = 1..18

我已经用谷歌搜索了它,但我找不到太多关于它的信息。问题是 PowerShell 没有将其视为一个范围,而是将其视为 1..18 字面意思。 因此,如果我执行 Write-Output $serverrange 它显示为“1..18”。所以我的问题是如何将其视为一个范围,或者如何更改脚本以合并该范围? 以下是脚本的其余部分:

     #user input for how many servers will be tested
     $numofservers = Read-Host -Prompt "How many servers are being tested?"
     if($numofservers -eq $serverrange) {
     "Proceed"
     } 
     else {
     "Server limit exceeded"
      }

编辑:没有意识到 $serverrange = 1..18 有效。

【问题讨论】:

  • 将范围括在引号中使其成为字符串。 [grin] 同样,Read-Host cal 返回 ... string。您的第二个示例给出了适当的范围,尝试使用 $VarName.GetType() 测试 $Variables 以查看变量中的内容。
  • 您想到哪种 .net 类型? .Net 是否像其他平台/语言一样具有某种“范围”类型?
  • @Lee_Dailey,感谢您的回答。我没有意识到第二个选项有效,我的错。如果用户输入在此范围内,您知道如何使用户输入显示“继续”吗?
  • @techguy1029 - 你的测试是针对$ServerLimit 但我看不出你在哪里设置的。如果您想查看 $numofservers 是否在范围内,请将其强制为 [int],然后使用 $numofservers -in $serverrange
  • 成功了!谢谢

标签: powershell variables scripting range


【解决方案1】:

正如您已经意识到的那样,未引用 表达式(例如 1..18)可以正常工作:它使用 PowerShell 的 range operator (..) 创建一个数组从118 的连续整数;即,它相当于以下数组 literal

 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18

相比之下,"1..18" 是一个(可扩展的)字符串,其内容按原样打印(在本例中为字面值1..18,因为该字符串不包含任何内容变量引用或子表达式)。

重要提示:虽然 技术上 可以使用 Invoke-Expression字符串 评估为 PowerShell 声明(例如,Invoke-Expression "1..18"),这种方法应该避免Invoke-Expression很少是正确的工具并且存在安全风险,尤其是在用户输入未经处理的情况下 - 请参阅the PowerShell-team blog post entitled "Invoke-Expression considered harmful"

您的挑战似乎是根据用户输入创建这样一个范围,默认情况下这是一个字符串,由@987654335返回@。

范围运算符能够动态将任一操作数(范围端点)转换为整数,并且乐意接受表达式为范围端点

1..(Read-Host 'Enter the upper bound') 

如果您输入3(如前所述,它以字符串的形式返回),PowerShell 会将该字符串动态转换为其等效整数并创建数组1..3,其默认输出如下所示这个:

1
2
3

也就是说,为了 (a) 提供用户友好的提示 (b) 强制执行预定义的输入范围(数字),还需要做更多的工作

因此:

  • 确保用户输入的内容可以转换为(a)一个数字,它(b)在预期范围内;如果没有,请再次提示。

  • 收到有效输入后,根据需要使用 PowerShell 的范围运算符 (..) 构造索引数组。

# Define the implied lower bound and the maximum upper bound.
$lowerBound = 1
$maxUpperBound = 18

# Prompt the user for the upper bound of the range, with validation,
# until a valid value is entered.
do {
  $userInput = Read-Host -Prompt "How many servers are being tested?"
  if (
    ($upperBound = $userInput -as [int]) -and 
    ($upperBound -ge $lowerBound -and $upperBound -le $maxUpperBound)
  ) {
    break # valid value entered, exit loop.
  } else {
    # Invalid input: Warn, and prompt again.
    Write-Warning "'$userInput' is either not a number or is outside the expected range of [$lowerBound,$maxUpperBound]."
  }
} while ($true)

# Create the array of indices based on user input.
1..$upperBound

【讨论】:

  • 是的,我用谷歌搜索了你所说的内容,我还想提供更多信息,说明 Invoke-Expression 为什么不是很安全。挺有趣的。作为一个新的powershell用户,我不知道。 community.idera.com/database-tools/powershell/powertips/b/tips/…
  • 那么,如果Invoke-Expression 不可行,您建议如何处理从文本文件 (example) 中获取的范围?是否有替代方案,例如"1..10" -as [???] 或一种方式,例如Get-Content 将字符串解释为范围还是整数?
  • @FatalBulletHit [int] $from, [int] $to = "1..10" -split '\.\.'; $from..$to
【解决方案2】:

这对我有用:

> $p = 1..18
> $p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>

使用: PS版本 5.1.14393.1944

【讨论】:

    【解决方案3】:

    如果你有一个字符串“1..18”,那么你可以使用invoke-expression来评估它,例如:

    PS C:\Users\chris> $s = "1..18"
    PS C:\Users\chris> $s
    1..18
    PS C:\Users\chris> $r = invoke-expression $s
    PS C:\Users\chris> $r
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    PS C:\Users\chris>
    

    【讨论】:

    • 感谢您提供额外信息。如何让脚本接受范围?如果我在 1 以外的范围内输入任何数字,我会收到第二条消息而不是第一条消息。
    • 您可以使用-contains,例如$x = "2" ; if (1..18 -contains $x) { "Gotcha" }.
    • 虽然您的解决方案在技术上有效,但Invoke-Expression should be avoided:它很少是正确的工具并且存在安全风险。
    猜你喜欢
    • 1970-01-01
    • 2012-03-08
    • 2017-06-20
    • 2015-05-02
    • 2014-09-24
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    • 2015-07-02
    相关资源
    最近更新 更多