2016-07-26 16 views
13

Gần đây, chúng tôi đã cập nhật phiên bản Powershell trên các máy chủ xây dựng của chúng tôi từ 4.0 đến 5.0. Thay đổi này đã khiến một trong các kịch bản xây dựng của chúng tôi bắt đầu bị lỗi một cách bất ngờ.Thay đổi trong Powershell 5 thay đổi ý nghĩa của các dấu ngoặc nhọn khối

Mã được sử dụng để xác định hướng dẫn sử dụng nào nên được bao gồm trong sản phẩm của chúng tôi. Mã xử lý danh sách các nút xml mô tả tất cả các tài liệu có sẵn với phiên bản và văn hóa. Chúng tôi nhóm theo tiêu đề tài liệu và văn hóa và sau đó chọn phiên bản phù hợp nhất.

$documents = Get-ListItemsFromSharePoint 
$documents = $documents | 
    Where-Object { $productVersion.CompareTo([version]$_.ows_Product_x0020_Version) -ge 0 } | 
    Where-Object { -not ($_.ows_EncodedAbsUrl.Contains('/Legacy/')) } 

Write-Verbose -Message "Filtered to: $($documents.length) rows" 

# Filter to the highest version for each unique title per language 
$documents = $documents | Group-Object { $_.ows_Title, $_.ows_Localisation } | 
    ForEach-Object { 
     $_.Group | Sort-Object { [version]$_.ows_Product_x0020_Version } -Descending | Select-Object -First 1 
    } 

Trong Powershell 4 mã này sắp xếp chính xác tài liệu theo tiêu đề và văn hóa rồi chọn phiên bản phù hợp nhất. Trong Powershell 5 mã này nhóm tất cả các tài liệu trong một danh sách duy nhất và sau đó chọn phiên bản phù hợp nhất từ ​​danh sách đó. Do chúng tôi có tài liệu bằng nhiều ngôn ngữ, điều này có nghĩa là chỉ có ngôn ngữ có phiên bản phù hợp nhất.

Vấn đề này đã được cố định bằng cách thay đổi

$documents = $documents | Group-Object { $_.ows_Title, $_.ows_Localisation } | 

để

$documents = $documents | Group-Object ows_Title, ows_Localisation | 

Bây giờ tôi hiểu rằng cú pháp đầu tiên là không đúng về mặt kỹ thuật theo tài liệu do Tập đoàn-Object mong đợi một loạt các tên thuộc tính để nhóm, tuy nhiên trong Powershell 4 mã đã trả lại kết quả mong muốn.

Câu hỏi giờ đây là những gì đã thay đổi trong Powershell 5 rằng mã gốc làm việc trong Powershell 4 nhưng thất bại trong Powershell 5.

+0

Tôi thấy như vậy nếu tôi kiểm tra các tệp nhóm ('ls | group {$ _. Length, $ _. Name} '). Không giống như tài liệu cho [PSv4] (https://technet.microsoft.com/library/hh849907.aspx) và [PSv5] (https://technet.microsoft.com/en-gb/library/hh849907 (v = wps.630) .aspx) phản ánh bất kỳ thay đổi nào. Xem ví dụ 3 và 6 - đó là cú pháp hợp lệ cho thuộc tính được tính. Cảm giác của tôi là v4 scriptblock trả về một mảng, mỗi mục được chuyển thành chuỗi và sau đó hoạt động như truyền một mảng các thuộc tính, và trong PSv5 kết quả của scriptblock được chuyển thành một chuỗi và được sử dụng như một tên thuộc tính. – TessellatingHeckler

+0

Tôi không tin rằng việc sử dụng {...} với đối tượng nhóm đã bao giờ đúng về mặt kỹ thuật ... có lẽ nó hoạt động giống như đối tượng foreach và ở đâu = đối tượng? Trừ khi có tài liệu ai đó có với Group-Object {...} –

+0

Trên suy nghĩ thứ hai, nó xuất hiện tuyên bố nên có được '$ tài liệu = $ tài liệu | Group-Object -Property {$ _. Ows_Title, $ _. Ows_Localisation} 'tất cả cùng ... –

Trả lời

6

Nó không giống như cú pháp của lệnh Nhóm-Object đã được thay đổi, như sau chương trình định nghĩa tương tự (cùng với các DLL mà phương pháp được định nghĩa) cho cả hai phiên bản:

gcm Group-Object | fl DLL,Definition 


DLL  : C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.PowerShell.Commands.Utility\v4.0_ 
      3.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.Commands.Utility.dll 
Definition : 
      Group-Object [[-Property] <Object[]>] [-NoElement] [-AsHashTable] [-AsString] 
      [-InputObject <psobject>] [-Culture <string>] [-CaseSensitive] [<CommonParameters>] 

Nhưng khi PetSerAL đề cập trong một chú thích nó trông giống như 5.0 DLL xử lý mảng khác biệt so với 4.0. Ví dụ:

$a=[PSCustomObject]@{[email protected](1,2)} #Object with an array for the value of the item property 
$b=[PSCustomObject]@{[email protected](3,3)} #Object with a different array for the value of the item property 
$a.item.Equals($b.item) #This deep compare is false, as the two objects are not equal 
$a.item.GetType().Equals($b.item.GetType()) #This "shallow" compare is true because both are the array type. 
$c=[PSCustomObject]@{[email protected]{key='value'}} #Similar but this time the item value is a hashtable 
$d=[PSCustomObject]@{[email protected]{anotherkey='anothervalue'}} #again comparing the two items we expect the result to be false if deep compared but true if shallow compared 
$e=[PSCustomObject]@{item=get-date} #another test using two datetimes (another common "reference" type) 
$f=[PSCustomObject]@{item=[datetime]::MinValue} 
$a,$b,$c,$d,$e,$f | group -Property item #now we see what happens when using group-object 

#Output in PowerShell 4.0 
Count Name      Group 
----- ----      ----- 
    1 {1, 2}     {@{item=System.Object[]}} 
    1 {3, 3}     {@{item=System.Object[]}} 
    2 {System.Collections.Di... {@{item=System.Collections.Hashtable}, @{item=System.Collections... 
    1 8/5/2016 9:45:36 PM  {@{item=8/5/2016 9:45:36 PM}} 
    1 1/1/0001 12:00:00 AM  {@{item=1/1/0001 12:00:00 AM}} 

#Output in PowerShell 5.0 
Count Name      Group 
----- ----      ----- 
    2 {1, 2}     {@{item=System.Object[]}, @{item=System.Object[]}} 
    2 {System.Collections.Di... {@{item=System.Collections.Hashtable}, @{item=System.Collections... 
    1 8/5/2016 9:45:40 PM  {@{item=8/5/2016 9:45:40 PM}} 
    1 1/1/0001 12:00:00 AM  {@{item=1/1/0001 12:00:00 AM}} 

Lưu ý rằng trong phiên bản 4 giá trị mảng được coi là nhóm riêng biệt, nhưng bảng băm được coi là nhóm bằng nhau. Điều đó có nghĩa là mảng có một so sánh sâu, nhưng hashtables là một so sánh nông (tất cả hashtables được coi là tương đương)

Bây giờ trong phiên bản 5 mảng được coi là tương đương, có nghĩa là chúng nông so sánh với cách hashtables làm việc.

Nếu bạn muốn xem chi tiết đầy đủ, bạn sẽ cần sử dụng ilspy hoặc .Net Reflector để tháo rời tệp DLL và so sánh phương thức DoGrouping của lớp Microsoft.PowerShell.Commands.GroupObjectCommand. Thật khó để nói nếu nó là một lỗi hay không, nhưng nó chắc chắn là một thay đổi phá vỡ cho cmdlet nhóm đối tượng.

Cập nhật: Tôi càng chơi càng nhiều thì tôi nghĩ mã mới là chính xác (ngoại trừ tên được hiển thị chỉ là System.Object) và có lỗi trong mã cũ. Có vẻ như v4 đã làm một số loại so sánh dựa trên chuỗi, vì ngay cả hai mảng khác nhau có cùng các thành phần sẽ được nhóm lại với nhau, mặc dù $a.Equals([PSCustomObject]@{[email protected](1,2)}) luôn sai (kết quả của phương thức GetHashCode không khớp). Cách duy nhất tôi có thể nhận được 5,0 để nhóm các mảng tương tự là sử dụng group -Property {$_.item -join ','}, phù hợp với đầu ra 4.0 ngoại trừ tên là 1,2 thay vì {1, 2}.Ngoài ra nếu bạn muốn nhóm bằng cách sử dụng khóa của mục có thể chia sẻ, bạn sẽ sử dụng group -Property {$_.item.somekey} (giả sử tất cả đều có giá trị cho khóa)

Các vấn đề liên quan