如何在PowerShell中将变量定义为范围?

3

我想要将一个变量设置为一个范围。我的脚本包括用户输入,而且这个输入必须在一定范围内。我将在脚本中多次使用这个范围,因此我希望它是一个变量。 这是我尝试过的:

    $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 可以工作。


1
将范围用引号括起来,就变成了一个“字符串”。[微笑] 此外,Read-Host 命令返回的是一个“字符串”。你的第二个示例给出了一个正确的范围,请尝试使用 $VarName.GetType() 来测试 $Variables 变量中包含的内容。 - Lee_Dailey
你考虑的是哪种 .Net 类型?.Net 是否有像其他平台/语言一样的“范围”类型? - Gert Jan Kraaijeveld
@Lee_Dailey,感谢您的回答。我没有意识到第二个选项是有效的,我的错。您知道如何使用户输入在此范围内时显示“继续”吗? - techguy1029
@techguy1029 - 你的测试是针对 $ServerLimit 的,但我没有看到你在哪里设置它。如果你想查看 $numofservers 是否在范围内,强制将其转换为 [int],然后使用 $numofservers -in $serverrange - Lee_Dailey
那个有效了!谢谢。 - techguy1029
3个回答

9

正如您已经意识到的那样,像1..18这样的未引用表达式完全可以正常工作:它使用了PowerShell的范围运算符 (..)来创建一个由连续整数组成的数组,从118; 即,它相当于以下数组字面量

 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很少是正确的工具,并且存在安全风险,尤其是对于未经过消毒的用户输入,请参见PowerShell团队发表的名为“Invoke-Expression considered harmful”的博客文章您的挑战似乎是基于用户输入创建这样的范围,默认情况下该输入是一个字符串,由Read-Host返回。 范围运算符能够动态地将任一操作数(范围端点)转换为整数,并且乐意接受表达式作为范围端点
1..(Read-Host 'Enter the upper bound') 

如果你输入 3 (正如所述,它被返回为一个字符串),PowerShell 会动态地将该字符串转换为其整数等价物,并创建数组1..3,其默认输出如下所示:
1
2
3

话虽如此,为了提供用户友好的提示并强制执行预定义的输入范围(数字),需要更多的工作。

因此:

  • 确保用户输入的内容可以转换为(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

1
是的,我已经按照你所说的进行了谷歌搜索,并且我也想提供更多关于为什么Invoke-Expression不太安全的信息。这很有趣。作为一个相对新的PowerShell用户,我毫不知情。https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/why-invoke-expression-is-evil - techguy1029
那么,如果Invoke-Expression不是解决问题的方法,你会建议如何处理从文本文件中获取的范围(例如:https://pastebin.com/Yi5SeynY)?是否有替代方案,例如:"1..10" -as [???]或者让Get-Content将字符串解释为范围或整数的方法? - FatalBulletHit
1
@FatalBulletHit [int] $from, [int] $to = "1..10" -split '\.\.'; $from..$to 解释:这是一行powershell代码,它将字符串“1..10”拆分成两个整数$from和$to,并使用点点运算符返回从$from到$to的数组。 - mklement0

2
如果您有一个字符串"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以外的任何数字,我会得到第二个消息而不是第一个。 - techguy1029
你可以使用-contains,例如:$x = "2" ; if (1..18 -contains $x) { "Gotcha" } - Chris J
2
虽然你的解决方案在技术上是可行的,但应该避免使用Invoke-Expression:它很少是正确的工具,并且存在安全风险。 - mklement0

1
这对我有效:

这适用于我:

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

使用: PSVersion 5.1.14393.1944

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接