2012-06-19 41 views
62

Tôi đang sử dụng Powershell để thiết lập các ràng buộc IIS trên một máy chủ web, và gặp vấn đề với đoạn mã sau:Làm cách nào để buộc Powershell trả về mảng khi cuộc gọi chỉ trả về một đối tượng?

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

Nếu có 2+ IP trên máy chủ, phạt tiền - Powershell trả về một mảng, và Tôi có thể truy vấn chiều dài mảng và trích xuất các địa chỉ đầu tiên và thứ hai tốt.

Vấn đề là - nếu chỉ có một IP, Powershell không trả về mảng một phần tử, nó trả về địa chỉ IP (như một chuỗi, như "192.168.0.100") - chuỗi có thuộc tính .length, lớn hơn 1, vì vậy kiểm tra sẽ trôi qua và tôi kết thúc với hai ký tự đầu tiên trong chuỗi, thay vì hai địa chỉ IP đầu tiên trong bộ sưu tập.

Làm thế nào tôi có thể buộc Powershell trả lại một bộ sưu tập một phần tử, hoặc cách khác xác định xem "điều" trả về có phải là một đối tượng thay vì một bộ sưu tập không?

+0

-tay đơn gây phiền nhiễu/khía cạnh bug-ridden Hầu hết PowerShell .. – user2864740

Trả lời

79

Xác định các biến như một mảng theo một trong hai cách ...

Quấn lệnh đường ống của bạn trong ngoặc với một @ tại phần đầu:

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

Chỉ định kiểu dữ liệu của biến dạng array:

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

Hoặc, kiểm tra kiểu dữ liệu của biến ...

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

Việc gói lệnh trong' @ (...) 'sẽ trả về một mảng ngay cả khi không có đối tượng bằng 0. Trong khi gán kết quả cho biến '-tym '' -typed sẽ vẫn trả về $ null nếu không có đối tượng nào. – Nic

+0

Chỉ cần lưu ý rằng không có giải pháp nào trong số này hoạt động nếu đối tượng được trả về là một PSObject (có thể là các đối tượng khác). –

+1

@ Deadly-Bagel Bạn có thể cho ví dụ về điều này không? Đối với tôi '@ (...)' hoạt động đúng (tạo ra kết quả tôi mong đợi nó sẽ tạo ra) cho bất kỳ loại đối tượng nào. – PetSerAl

9

Buộc kết quả vào một mảng để bạn có thể có thuộc tính Đếm. Các đối tượng đơn (vô hướng) không có thuộc tính Đếm. Strings có một tài sản dài, do đó bạn có thể nhận được kết quả sai, sử dụng thuộc tính Count:

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

Bằng cách này, thay vì sử dụng một ký tự đại diện mà cũng có thể phù hợp với chuỗi, sử dụng toán tử -Như:

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

Đối với điều này có thể không ông cũng chỉ cần kiểm tra kiểu dữ liệu với '-is '? – JNK

+0

Chuỗi có thuộc tính .length - đó là lý do tại sao nó hoạt động ... :) –

+0

Đúng, sẽ sửa lỗi này ngay lập tức. –

5

Nếu bạn khai báo các biến như một mảng trước thời hạn, bạn có thể thêm các yếu tố vào nó - ngay cả khi nó chỉ là một ...

Điều này sẽ hoạt động ...

$serverIps = @() 

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

Tôi thực sự cảm thấy như đây là lựa chọn rõ ràng và an toàn nhất. Bạn có thể sử dụng đáng tin cậy ".Count - ge 1" trên bộ sưu tập hoặc 'Foreach' –

0

Tôi gặp sự cố này khi chuyển mảng tới mẫu triển khai Azure. Nếu có một đối tượng, PowerShell "chuyển đổi" nó thành một chuỗi. Trong ví dụ bên dưới, $a được trả về từ một hàm bị VM phản đối theo giá trị của thẻ. Tôi chuyển số $a tới lệnh ghép ngắn New-AzureRmResourceGroupDeployment bằng cách gói nó trong @(). Giống như vậy:

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

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

VMObject là một trong các tham số của mẫu.

Có thể không phải là cách kỹ thuật/mạnh mẽ nhất để làm điều đó, nhưng nó đủ cho Azure.


Cập nhật

Vâng ở trên đã làm việc. Tôi đã thử tất cả ở trên và một số, nhưng cách duy nhất tôi đã quản lý để vượt qua $vmObject như là một mảng, tương thích với mẫu triển khai, với một yếu tố như sau (tôi mong đợi MS đã được chơi một lần nữa (đây là một báo cáo và lỗi cố định vào năm 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 là đầu ra của Get-AzureRmVM.

Tôi chuyển $DeserializedJson tham số mẫu triển khai (của mảng loại).

Để tham khảo, các lỗi đáng yêu New-AzureRmResourceGroupDeployment ném là

"The template output '{output_name}' is not valid: The language expression property 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Expression.Expressions.JTokenExpression' 
can't be evaluated.." 
Các vấn đề liên quan