2012-06-19 9 views
62

Używam PowerShell do utworzenia wiązań IIS na serwerze WWW, a problem z następującego kodu:Jak zmusić Powershell do zwrócenia tablicy, gdy wywołanie zwraca tylko jeden obiekt?

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

Jeśli istnieje 2+ IP na serwerze, w porządku - PowerShell zwraca tablicę, a Mogę zapytać o długość tablicy i wyodrębnić pierwszy i drugi adres.

Problem polega na tym, że jeśli istnieje tylko jeden adres IP, Powershell nie zwraca tablicy jednoelementowej, zwraca adres IP (jako ciąg znaków, np. "192.168.0.100") - ciąg ma właściwość .length, jest większy niż 1, więc test przechodzi, a ja kończę na pierwszych dwóch znakach w ciągu, zamiast dwóch pierwszych adresów IP w kolekcji.

W jaki sposób można zmusić Powershell do zwrócenia kolekcji jednego elementu, lub alternatywnie określić, czy zwrócona "rzecz" jest obiektem, a nie zbiorem?

+0

Większość pojedynkę irytujące/bug-jeździł aspekt PowerShell .. – user2864740

Odpowiedz

79

Zdefiniuj zmienną jako tablicę w jeden z dwóch sposobów ...

owinąć rurami polecenia w nawiasach z @ na początku:

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

określić typ danych zmiennej jako tablica:

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

Albo sprawdzić typ danych zmiennej ...

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

Zawijanie polecenia w' @ (...) 'zwróci tablicę, nawet jeśli istnieją zero obiektów. Natomiast przypisanie wyniku zmiennej '[Array]' -typed nadal zwróci wartość $ null, jeśli są zero obiektów. – Nic

+0

Wystarczy zauważyć, że żadne z tych rozwiązań nie działa, jeśli zwróconym obiektem jest PSObject (prawdopodobnie inne). –

+1

@ Deadly-Bagel Czy możesz pokazać przykład tego? Dla mnie '@ (...)' działa poprawnie (generuje wynik, który powinien być generowany) dla dowolnego typu obiektów. – PetSerAl

9

Wymuś wynik w tablicy, abyś mógł mieć właściwość Count. Pojedyncze obiekty (skalarne) nie mają właściwości Count. Struny mają właściwość length więc można uzyskać fałszywe wyniki, należy użyć właściwości Count:

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

Nawiasem mówiąc, zamiast przy użyciu symboli wieloznacznych, które można również dopasować ciągi, należy użyć operatora -as:

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

Do tego nie może też po prostu sprawdzić typ danych z '-is '? – JNK

+0

Ciągi mają właściwość .length - dlatego działa ... :) –

+0

Prawidłowo, naprawię to od razu. –

5

Jeśli zadeklarujesz zmienną jako tablica z wyprzedzeniem, możesz dodać do niej elementy - nawet jeśli to tylko jeden ...

To powinno zadziałać ...

$serverIps = @() 

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

Rzeczywiście czuję, że jest to najbardziej przejrzysta i bezpieczna opcja. Możesz niezawodnie używać ".Count - ge 1" w kolekcji lub "Foreach" –

0

Miałem ten problem, przekazując tablicę do szablonu wdrażania Azure. Jeśli był jeden obiekt, PowerShell "przekonwertował" go na ciąg znaków. W poniższym przykładzie zwracana jest funkcja $a z funkcji, która powoduje, że maszyny wirtualne są zgłaszane zgodnie z wartością znacznika. Przekazuję $a do cmdletu New-AzureRmResourceGroupDeployment, owijając go w @(). Tak jak poniżej:

[email protected]{ 
    [email protected]($a) 
} 

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

VMObject jest jednym z parametrów szablonu.

Może nie jest to najbardziej techniczny/niezawodny sposób, ale wystarczy na Azure.


Aktualizacja

Dobrze wyżej wyszło. Próbowałem wszystkich powyższych i niektórych, ale jedyny sposób, w jaki udało mi się przekazać $vmObject jako tablicę, zgodną z szablonem wdrażania, z jednym elementem jest następujący (oczekuję, że MS grają ponownie (był to raport i poprawiony błąd w 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 jest wyjście Get-AzureRmVM.

Przekażę $DeserializedJson do parametru szablonu wdrażania (z tablicy typów).

Dla porównania, piękny błąd New-AzureRmResourceGroupDeployment rzuca to

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