异常的变量类型不匹配

Unusual variable type mismatches

如果我运行命令:

Resize-VHD -ComputerName $VMhost -Path "D:\VMs$VMname\Virtual Hard Disks$vmname.vhdx" -SizeBytes 70GB

Powershell 足够聪明,可以理解 70GB 是什么,接受争论并调整驱动器大小,

但是,如果我这样做:

$drivesize = "70GB"

Resize-VHD -ComputerName $VMhost -Path "D:\VMs$VMname\Virtual Hard Disks$vmname.vhdx" -SizeBytes $drivesize

我收到以下错误:

Resize-VHD : Cannot bind parameter 'SizeBytes'. Cannot convert value "70GB" to type "System.UInt64". Error: "Input string was 
not in a correct format."
At line:22 char:100
+ ... D:\VMs$VMname\Virtual Hard Disks$vmname.vhdx" -SizeBytes $drivesize
+                                                                ~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (:) [Resize-VHD], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Vhd.PowerShell.Cmdlets.ResizeVhd

我认为这是一个变量类型的问题,错误说了这么多,我只是不知道如何解决它。

编辑:

如果我将 $drivesize 的值写入控制台,我得到:

PS C:\Windows\system32> $drivesize
70GB

而不是:

$drivesize = "70GB" # WRONG: Quoting creates a STRING, but you want a NUMBER

使用:

$drivesize = 70GB  # OK: 70GB is a NUMBER LITERAL, evaluating to 75161927680 

对于 PowerShell,带有二进制乘数后缀的不带引号的数字标记 例如 GB 数字 .
注意结果数的特定整数类型变化:等于或大于[int]的最小有符号整数类型(System.Int32) 可以适合的数字被使用;例如,1GB 创建一个 [int],而上面的示例 70GB 创建一个 [long] (System.Int64).
不过,通常情况下,您不必担心 PowerShell 中的特定数字类型,因为它们会按需相互转换。

不要将此类标记存储在 strings 中;虽然 PowerShell 在将看起来像数字的字符串转换为实际数字时通常非常灵活,但它通常 不会 "70GB" 等字符串识别为数字 - 见下文。


可选阅读:字符串的数字转换,包含带有后缀的数字标记,例如GB

也许令人惊讶的是,PowerShell 的二进制乘数后缀 - kbmbgbtbpb - 仅在数字 文字 中工作,而不是在(隐式)从字符串 转换 .

PS> 1gb  # produces an [int] whose value is equivalent to 1 * [math]::Pow(2, 30)
1073741824

PS> [int] '1gb' # !! From-string conversion FAILS
Cannot convert value "1gb" to type "System.Int32". Error: "Input string was not in a correct format."

# Workaround: Simply divide by 1, because PowerShell does
#             recognize the suffix in the context of an *expression*.
PS> '1gb' / 1
1073741824

感谢 PetSerAl 提供解决方法。
[自 PowerShell (Core) 7+] 在 表达式 中执行隐式到数字转换时识别后缀与 之间令人惊讶的差异=61=]参数绑定在this GitHub issue中讨论。

从字符串转换不起作用的原因是后缀是 PowerShell 特定的,而将字符串转换为数字类型 - 无论是在参数绑定期间隐式还是显式地使用诸如 [int] 之类的强制转换 - 使用 .NET 方法 ,这些方法不知道这些后缀。

因此,使用表达相同值的字符串 没有 乘数后缀会有效,例如:

PS> $driveSize = '1073741824'; [UInt64] $driveSize
1073741824

尽管如果您事先知道该值,则没有理由使用字符串开头,使用数字文字可以避免问题:

$driveSize = 70GB # creates a [long] (System.Int64) with value 75161927680

请注意,PowerShell 通常会根据需要扩展数字类型(根据需要使用更大容量的类型)并自动执行 signed/unsigned 类型转换。

因此,即使 $driveSize 是基于上述语句的 System.Int64 类型,PowerShell 在绑定到 SizeBytes 时会自动将其转换为 System.UInt64(无符号)参数.