Необычные несоответствия типов переменных - PullRequest
0 голосов
/ 05 сентября 2018

Если я запускаю команду:

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

Powershell достаточно умен, чтобы понять, что такое 70 ГБ, принять аргументацию и изменить размер диска,

Однако, если я сделаю:

$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

Я думаю, что это проблема типа переменной, ошибка говорит о многом, я просто не знаю, как ее исправить.

Edit:

Если я записываю значение $drivesize в консоль, я получаю:

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

1 Ответ

0 голосов
/ 05 сентября 2018

Вместо:

$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, потому что они преобразовываются друг в друга по требованию.

Не хранить такие токены в строках ; в то время как PowerShell, как правило, очень гибок в преобразовании строк, которые выглядят как числа, в реальные числа, он обычно не распознает такие строки, как "70GB", как числа - см. ниже.


Необязательное чтение: Преобразование в число строки , содержащей числовой токен с суффиксом, таким как GB

Возможно, что удивительно, суффиксы двоичного множителя PowerShell - kb, mb, gb, tb, pb - работают только с числом литералов , а не когда (неявно) преобразование из строки .

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 для обеспечения обходного пути.
Удивительное расхождение между распознаванием суффиксов при выполнении неявных преобразований в числа в выражениях по сравнению с тем, когда привязка параметров обсуждается в этой проблеме GitHub .

Причина, по которой преобразование из строки не работает, заключается в том, что суффиксы специфичны для PowerShell , тогда как преобразование строки в числовой тип - неявно во время привязки параметра или явно с приведением типа [int] - использует .NET методы , которые не знают этих суффиксов.

Поэтому, используя строку, которая выражает то же значение без , сработал бы суффикс множителя, например:

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

Хотя, если вы знаете значение заранее, нет смысла использовать строку для начала, а использование числового литерала устраняет проблему:

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

Обратите внимание, что PowerShell обычно расширяет числовые типы по требованию (при необходимости использует типы большей емкости) и автоматически выполняет преобразования типов со знаком / без знака.

Следовательно, даже если $driveSize имеет тип System.Int64, основанный на приведенном выше утверждении, PowerShell автоматически преобразует его в System.UInt64 (без знака) при привязке к параметру SizeBytes.

...