【问题标题】:PowerShell multiplier not recognized using Read-Host使用读取主机无法识别 PowerShell 乘数
【发布时间】:2021-11-18 20:30:44
【问题描述】:

有没有办法让 Read-Host 识别 KB、MB、GB、TB 和 PB 等 PowerShell 乘数?如果我手动填充 $freespace 变量,第一个示例可以正常工作,但在使用 Read-Host 填充 $freespace 变量的第二个示例中不起作用。必须是一个简单的解决方案,以便提示用户输入并将值识别为整数而不是字符串。

#this works just fine. The PowerShell multiplier GB is recognized if typed in.

$freespace = 6GB

If ($freeSpace -le 5GB) {
    Write-Host “Free disk space is less than 5 GB”
} ElseIf ($freeSpace -le 10GB) {
    Write-Host “Free disk space is less than 10 GB”
} ElseIf ($freeSpace -le 20GB) {
    Write-Host “Free disk space is less than 20 GB”
} Else {
    Write-Host “Free disk space is more than 20 GB”
}

#This does not work. The variable is populated by Read-Host as a [string] 

$freespace = Read-Host -Prompt 'Please enter a value for Freespace'

If ($freeSpace -le 5GB) {
    Write-Host “Free disk space is less than 5 GB”
} ElseIf ($freeSpace -le 10GB) {
    Write-Host “Free disk space is less than 10 GB”
} ElseIf ($freeSpace -le 20GB) {
    Write-Host “Free disk space is less than 20 GB”
} Else {
    Write-Host “Free disk space is more than 20 GB”
}

【问题讨论】:

  • $freespace = Invoke-Expression $freespace。在这里使用 iex 因为我不确定 调用运算符 在这种情况下是否可以工作(&)(不在我的办公桌上进行测试 )。您正在向它传递一个字符串,它将被按原样读取。您必须允许执行表达式。
  • @AbrahamZinala - 这会起作用,但它也会执行remove-item c:\* -rec -force -ea continue。根据脚本呈现给用户的方式,这可能存在安全风险。
  • @Lieven,不确定如何根据显示为 “请输入可用空间的值” 的提示输入整个 cmdlet。与只是说在 shell 本身中执行 Remove-Item c:\ -Recurse 会很危险没有什么不同......但是,我明白你的意思。我们可以通过解析数据并评估传递给变量的内容来解决它。你会推荐什么?
  • 通常的解决方法是转换为数值。一种安全的方法是使用 -as 运算符(请参阅我的答案)。
  • @AbrahamZinala - 我应该更多地关注取决于脚本如何呈现给用户。如果脚本使用备用凭据运行,它可能允许用户执行他无权执行的命令。

标签: powershell read-host


【解决方案1】:

当你这样做时:

$freespace = Read-Host -Prompt 'Please enter a value for Freespace'

$freespace 变量中存储的值将是[String] 类型,而您可能需要[UInt64](正整数)。您可以使用如下代码将[String] 类型转换为[UInt64] 类型:

do {
  $entry = Read-Host "Please enter a value for freespace, in GB"
  $freespace = $entry -as [UInt64]
  $ok = ($null -ne $freespace) -and ($freespace -lt 1024)
  if ( -not $ok ) {
    Write-Host "Please enter a value in the range 0 to 1023"
  }
until ( $ok )
$freespace *= 1GB

首先,您提示输入[String] 并将其存储在$entry 中。接下来,我们使用-as 运算符将字符串值转换[UInt64] 值。如果转换失败,$freespace 变量将包含$nulldo 循环将重复,直到输入一个数值。

使用脚本中的上述代码,$freespace 将在 do 循环完成后成为一个数值。最后一行将其转换为 GB。

【讨论】:

    【解决方案2】:

    修正

    $freeSpace = $null
    do {
     [int]$freeSpaceRaw = Read-Host -Prompt 'Please enter a value for Freespace in GB example 5 for 5GB '
      try { $freeSpace = 0 + $freeSpaceRaw } catch { Write-Warning 'Please enter a valid number.' }
    } while ($null -eq $freeSpace)
    
    If ($freeSpace -lt 5) {
        "Free disk space is less than 5 GB"
    } ElseIf ($freeSpace -lt 10) {
        "Free disk space is less than 10 GB"
    } ElseIf ($freeSpace -lt 20) {
        "Free disk space is less than 20 GB"
    } Else {
        "Free disk space is more than 20 GB"
    }
    

    【讨论】:

    • 删除[int] 演员表,否则如果用户输入的值不能解释为字符串,您将收到一个实际上退出循环的错误。在元注释上:为了在发布后改进您的答案,编辑它们 - 不要将更新发布作为另一个答案。请删除您原来的答案。
    【解决方案3】:

    你的读取主机是一个字符串而不是一个 int 试试下面

    [int]$freespace = Read-Host -Prompt 'Please enter a value for Freespace'

    【讨论】:

    • 这将起作用,但前提是您输入一个数值。如果你输入一个非数字值,它会抛出一个错误(这可能不是你想要的)。我建议使用-as 进行投射(请参阅我的回答)。
    • 另请注意,OP 希望将诸如 '6GB' 之类的字符串识别为等效数字 (6442450944),这在 Windows PowerShell 中不适用于强制转换/类型约束,例如[long] '6GB';但是,它确实可以在 PowerShell (Core) 7+ 中使用。
    【解决方案4】:

    回答原来的问题:

    有没有办法让Read-Host 识别 KB、MB、GB、TB 和 PB 等 PowerShell 乘数?

    Windows PowerShell 识别 二进制乘数后缀 - kbmbgbtb、@987654328 @ - 仅在数字 literals 中,不是也用于(隐式)从字符串转换 ,后者是什么Read-Host cmdlet 总是返回。

    唯一可以识别字符串形式的上下文是基于运算符的表达式,其中字符串操作数被隐式转换为数字,这使得一个相当简单和安全的解决方法[1]

    # 0 + forces the RHS string to be converted to a number, which
    # in this particular context *does* work with binary multiplier suffixes 
    PS> 0 + '1kb'
    1024
    

    此解决方法也适用于 PowerShell (Core) 7+,但在那里您可以简单地使用
    [long] '1kb'
    ,因为现在在隐式到数字转换期间一致支持此类字符串

    应用于您的代码:

    while ($true) {
      try { 
        $freeSpace = 0 + (Read-Host -Prompt 'Please enter a value for Freespace')
        break # Valid input received; exit the loop.
      } catch { 
        Write-Warning 'Please enter a valid number.' # Prompt again.
      }
    }
    
    If ($freeSpace -lt 5GB) {
        "Free disk space is less than 5 GB"
    } ElseIf ($freeSpace -lt 10GB) {
        "Free disk space is less than 10 GB"
    } ElseIf ($freeSpace -lt 20GB) {
        "Free disk space is less than 20 GB"
    } Else {
        "Free disk space is more than 20 GB"
    }
    

    [1] 虽然使用 Invoke-Expression (iex) 在技术上也可以工作,但通常应该避免使用此 cmdlet,并且仅将其用作最后的手段,由于其固有的安全风险。通常有更好的替代品。如果确实没有其他选择,请仅在您自己提供或完全信任的输入中使用它 - 请参阅this answer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-08
      • 2012-08-06
      • 2021-12-31
      • 2015-05-26
      • 1970-01-01
      • 2021-01-13
      • 2020-12-18
      相关资源
      最近更新 更多