Bir çağrı yalnızca bir nesne döndürdüğünde Powershell'i bir dizi döndürmeye nasıl zorlayabilirim?


123

Powershell'i bir web sunucusunda IIS bağlamaları kurmak için kullanıyorum ve aşağıdaki kodla ilgili bir sorun yaşıyorum:

$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]

Sunucuda 2'den fazla IP varsa, iyi - Powershell bir dizi döndürür ve dizi uzunluğunu sorgulayabilir ve birinci ve ikinci adresleri gayet iyi çıkarabilirim.

Sorun - sadece bir IP varsa, PowerShell tek unsur dizisi dönmez, o ( "192.168.0.100" gibi bir dize olarak) IP adresini döndürür - dizesi vardır .length, böylece, mülkiyet 1'den 's büyüktür test başarılı oluyor ve koleksiyondaki ilk iki IP adresi yerine dizedeki ilk iki karakteri buluyorum.

Powershell'i tek öğeli bir koleksiyon döndürmeye nasıl zorlayabilirim veya alternatif olarak döndürülen "şey" in bir koleksiyondan ziyade bir nesne olup olmadığını nasıl belirleyebilirim?


29
PowerShell'in tek başına en can sıkıcı / hata dolu yönü ..
user2864740

Örneğinizi aşırı karmaşık buluyorum. Daha basit soru: << $ x = echo Merhaba; $ x -is [Dizi] >> False sonucunu verir.
Raúl Salinas-Monteagudo

bu davranış powershell 5'te değişti mi? 5'te yeniden oluşturamadığım, ancak 4'te yeniden oluşturabileceğim benzer bir sorun var
NickL

Yanıtlar:


143

Değişkeni iki yoldan biriyle bir dizi olarak tanımlayın ...

Borulu komutlarınızı @başında bir parantez içine alın :

$serverIps = @(gwmi Win32_NetworkAdapterConfiguration 
    | Where { $_.IPAddress } 
    | Select -Expand IPAddress 
    | Where { $_ -like '*.*.*.*' } 
    | Sort)

Değişkenin veri türünü bir dizi olarak belirtin:

[array]$serverIps = gwmi Win32_NetworkAdapterConfiguration 
    | Where { $_.IPAddress } 
    | Select -Expand IPAddress 
    | Where { $_ -like '*.*.*.*' } 
    | Sort

Veya değişkenin veri türünü kontrol edin ...

IF ($ServerIps -isnot [array])
{ <error message> }
ELSE
{ <proceed> }

28
Bir komutun içine sarılması @(...), sıfır nesne olsa bile bir dizi döndürür. Oysa, sonucu [Array]-tipli bir değişkene atamak, sıfır nesne varsa yine de $ null döndürür.
Nic

1
Döndürülen nesne bir PSObject ise (muhtemelen diğerleri) bu çözümlerden hiçbirinin işe yaramayacağını unutmayın.
Deadly-Bagel

2
@ Deadly-Bagel Bunun bir örneğini gösterebilir misiniz? Benim @(...)için herhangi bir nesne türü için düzgün çalışıyorum (üretmesini beklediğim sonucu üret).
user4003407

1
Aynı sorulara geri dönmen çok komik. Biraz farklı bir sorun yaşadım (ve yine yaşadım), evet soruda olduğu gibi bu iyi çalışıyor ancak bir işlevden döndüğümde bu farklı bir hikaye. Bir öğe varsa, dizi yok sayılır ve yalnızca öğe döndürülür. Değişkenin önüne virgül koyarsanız, onu bir diziye zorlar, ancak çok elemanlı bir dizi iki boyutlu bir dizi döndürür. Çok sıkıcı.
Deadly-Bagel

1
Gah, geçen sefer de bu oldu, şimdi kopyalayamıyorum. Her halükarda son problemimi Return ,$outher zaman işe yarıyor gibi görünen kullanarak çözdüm. Sorunla tekrar karşılaşırsam bir örnek göndereceğim.
Deadly-Bagel

14

Sonucu bir Diziye zorlayın, böylece bir Count özelliğine sahip olabilirsiniz. Tek nesnelerin (skaler) bir Count özelliği yoktur. Dizelerin uzunluk özelliği vardır, bu nedenle yanlış sonuçlar alabilirsiniz, Count özelliğini kullanın:

if (@($serverIps).Count -le 1)...

Bu arada, dizelerle de eşleşebilen bir joker karakter kullanmak yerine -as operatörünü kullanın:

[array]$serverIps = gwmi Win32_NetworkAdapterConfiguration -filter "IPEnabled=TRUE" | Select-Object -ExpandProperty IPAddress | Where-Object {($_ -as [ipaddress]).AddressFamily -eq 'InterNetwork'}

Bunun için veri tipini de kontrol edemez -ismi?
JNK

Dizelerin bir .length özelliği vardır - bu yüzden çalışıyor ... :)
Dylan Beattie

8

Değişkeni önceden bir dizi olarak bildirirseniz, ona elemanlar ekleyebilirsiniz - tek bir bile olsa ...

Bu çalışmalı...

$serverIps = @()

gwmi Win32_NetworkAdapterConfiguration 
    | Where { $_.IPAddress } 
    | Select -Expand IPAddress 
    | Where { $_ -like '*.*.*.*' } 
    | Sort | ForEach-Object{$serverIps += $_}

Aslında bunun en açık ve güvenli seçenek olduğunu hissediyorum. Koleksiyonu ya da 'ge 1' forEach' - Sen güvenilir ".Count kullanabilirsiniz
Jaigene Kang

2

Measure-ObjectBir nesnenin Countözelliğine başvurmadan gerçek nesne sayısını elde etmek için kullanabilirsiniz .

$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
}

1

,İade listesinden önce virgül ( ) ekleyebilir return ,$listveya yayınlayabilirsiniz [Array]ya [YourType[]]da listeyi kullanma eğiliminde olduğunuz yere.


0

Azure dağıtım şablonuna bir dizi geçirirken bu sorunu yaşadım. Bir nesne varsa, PowerShell onu bir dizeye "dönüştürür". Aşağıdaki örnekte $a, bir etiketin değerine göre VM'ye itiraz eden bir işlevden döndürülmüştür. Ben geçmesi $aiçin New-AzureRmResourceGroupDeploymentsararak cmdlet'indeki @(). Şöyle:

$TemplateParameterObject=@{
     VMObject=@($a)
}

New-AzureRmResourceGroupDeployment -ResourceGroupName $RG -Name "TestVmByRole" -Mode Incremental -DeploymentDebugLogLevel All -TemplateFile $templatePath -TemplateParameterObject $TemplateParameterObject -verbose

VMObject şablonun parametrelerinden biridir.

Bunu yapmanın en teknik / sağlam yolu olmayabilir, ancak Azure için yeterli.


Güncelleme

Yukarıdakiler işe yaradı. Yukarıdakilerin hepsini ve bazılarını denedim, ancak $vmObjectdağıtım şablonuyla uyumlu bir dizi olarak geçmeyi başardığım tek yol aşağıdaki gibidir (MS'nin tekrar oynamasını bekliyorum (bu bir rapordu ve düzeltildi) 2015'teki hata)):

[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'nin çıktısıdır.

Ben geçmek $DeserializedJson(tip dizisinin) dağıtım şablonun' parametresine.

Referans için, güzel hata New-AzureRmResourceGroupDeploymentatar

"The template output '{output_name}' is not valid: The language expression property 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Expression.Expressions.JTokenExpression' 
can't be evaluated.."

0

Referans verilen bir nesne olarak dönün, böylece geçerken asla dönüştürülmez.

return @{ Value = @("single data") }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.