Как заставить Powershell возвращать массив, когда вызов возвращает только один объект?
Я использую Powershell для настройки Привязок IIS на веб-сервере, и возникли проблемы со следующим кодом:
$serverIps = gwmi Win32_NetworkAdapterConfiguration
| Where { $_.IPAddress }
| Select -Expand IPAddress
| Where { $_ -like '*.*.*.*' }
| Sort
if ($serverIps.length -le 1) {
Write-Host "You need at least 2 IP addresses for this to work!"
exit
}
$primaryIp = $serverIps[0]
$secondaryIp = $serverIps[1]
Если на сервере есть 2 + IPs, fine-Powershell возвращает массив, и я могу запросить длину массива и извлечь первый и второй адреса просто отлично.
проблема - если есть только один IP, Powershell не возвращает одноэлементный массив, он возвращает IP-адрес (в виде строки, например "192.168.0.100") - строка имеет .length свойство, оно больше 1, поэтому тест проходит, и я получаю первые два символа в строке вместо первых двух IP-адресов в коллекции.
Как я могу либо заставить Powershell вернуть коллекцию из одного элемента, либо определить, является ли возвращаемая "вещь" объектом, а не коллекцией?
5 ответов:
определить переменную как массив можно одним из двух способов...
заключите ваши передаваемые команды в круглые скобки с помощью
@в начале:$serverIps = @(gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress } | Select -Expand IPAddress | Where { $_ -like '*.*.*.*' } | Sort)укажите тип данных переменной в виде массива:
[array]$serverIps = gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress } | Select -Expand IPAddress | Where { $_ -like '*.*.*.*' } | Sortили, проверьте тип данных переменной...
IF ($ServerIps -isnot [array]) { <error message> } ELSE { <proceed> }
принудительно результат в массив, так что вы могли бы иметь свойство Count. Отдельные объекты (скалярные) не имеют свойства Count. Строки имеют свойство length, поэтому вы можете получить ложные результаты, используйте свойство Count:
if (@($serverIps).Count -le 1)...кстати, вместо использования подстановочного знака, который также может соответствовать строкам, используйте оператор-as:
[array]$serverIps = gwmi Win32_NetworkAdapterConfiguration -filter "IPEnabled=TRUE" | Select-Object -ExpandProperty IPAddress | Where-Object {($_ -as [ipaddress]).AddressFamily -eq 'InterNetwork'}
Если вы объявите переменную как массив раньше времени, вы можете добавить в нее элементы - даже если это только один...
Это должно работать...
$serverIps = @() gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress } | Select -Expand IPAddress | Where { $_ -like '*.*.*.*' } | Sort | ForEach-Object{$serverIps += $_}
можно использовать
Measure-Objectчтобы получить фактическое количество объектов, не прибегая к объектуCountсобственность.$serverIps = gwmi Win32_NetworkAdapterConfiguration | Where { $_.IPAddress } | Select -Expand IPAddress | Where { $_ -like '*.*.*.*' } | Sort if (($serverIps | Measure).Count -le 1) { Write-Host "You need at least 2 IP addresses for this to work!" exit }
у меня была эта проблема с передачей массива в шаблон развертывания Azure. Если был один объект, PowerShell "преобразовал" его в строку. В приведенном ниже примере
$aвозвращается из функции, которая получает VM возражается в соответствии со значением тега. Я передаю$aдоNew-AzureRmResourceGroupDeploymentкомандлет, обернув его в@(). Вот так:$TemplateParameterObject=@{ VMObject=@($a) } New-AzureRmResourceGroupDeployment -ResourceGroupName $RG -Name "TestVmByRole" -Mode Incremental -DeploymentDebugLogLevel All -TemplateFile $templatePath -TemplateParameterObject $TemplateParameterObject -verbose
VMObjectявляется одним из параметров шаблона.возможно, это не самый технический / надежный способ сделать это, но это достаточно для Лазурного.
обновление
Ну выше действительно работал. Я пробовал все выше и некоторые, но только так мне удалось передать
$vmObjectкак массив, совместимый с шаблоном развертывания, с одним элементом выглядит следующим образом (я ожидаю, что MS снова играет (это был отчет и исправлена ошибка в 2015 году)):[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") foreach($vmObject in $vmObjects) { #$vmTemplateObject = $vmObject $asJson = (ConvertTo-Json -InputObject $vmObject -Depth 10 -Verbose) #-replace '\s','' $DeserializedJson = (New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer -Property @{MaxJsonLength=67108864}).DeserializeObject($asJson) }
$vmObjects- это выход Get-AzureRmVM.я пройти
$DeserializedJsonк параметру шаблона развертывания (of типизированный массив.)Для справки, прекрасная ошибка
New-AzureRmResourceGroupDeploymentвызывает"The template output '{output_name}' is not valid: The language expression property 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Expression.Expressions.JTokenExpression' can't be evaluated.."
Comments