Как заставить 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 вернуть коллекцию из одного элемента, либо определить, является ли возвращаемая "вещь" объектом, а не коллекцией?

571   5  

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

    Ничего не найдено.