2016-07-26 21 views
13

我們最近將構建服務器上的Powershell版本從4.0更新到了5.0。這一變化導致我們的一個構建腳本以意想不到的方式開始失敗。Powershell 5中的變化改變了塊花括號的含義

該代碼用於確定哪些用戶指南應該包含在我們的產品中。代碼處理一系列xml節點,這些節點用版本和文化描述所有可用的文檔。我們按文件標題和文​​化分組,然後選擇最合適的版本。

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

在Powershell 4中,此代碼正確地按標題和文化排序文檔,然後選擇最合適的版本。在Powershell 5中,此代碼將所有文檔分組在一個列表中,然後從該列表中選擇最合適的版本。鑑於我們擁有多種語言的文檔,這意味着只有具有最適合版本的語言纔會出現。

的問題是固定的,通過改變

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

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

現在我明白了第一種語法根據文檔,因爲集團的對象預計的屬性名稱的數組是技術上不正確分組,但是在Powershell 4中,代碼確實返回了期望的結果。

現在的問題是在PowerShell中5有什麼改變,原來的代碼在PowerShell中4工作,但在PowerShell中失敗了5

+0

如果我測試分組文件('ls | group {$ _。Length, $ _。名稱}')。看起來不像[PSv4](https://technet.microsoft.com/library/hh849907.aspx)和[PSv5](https://technet.microsoft.com/en-gb/library/hh849907)的文檔(v = wps.630).aspx)反映了任何更改。看例3和例6 - 這是一個計算屬性的有效語法。我的感覺是,在v4中,scriptblock返回一個數組,每個項目都轉換爲字符串,然後像傳遞一組屬性一樣,而在PSv5中,scriptblock的結果全部轉換爲一個字符串並用作一個屬性名稱。 – TessellatingHeckler

+0

我不認爲使用{...}與group-object在技術上是正確的......也許它看起來像foreach-object和where = object?除非有文檔有人與Group-Object {...} –

+0

第二個想法,它似乎聲明應該是'$ documents = $ documents | Group-Object -Property {$ _ .ows_Title,$ _ .ows_Localisation}'一直以來... –

回答

6

它看起來並不像小組對象cmdlet的語法被改變,而以下示出了相同的定義(與DLL沿着其中定義的方法),用於兩個版本:

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

但作爲PetSerAL中的評論中提及它看起來像5.0 DLL處理陣列不同於4.0。例如:

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

請注意,在版本4中,數組值被視爲單獨的組,但散列表被視爲相同的組。這意味着數組有很深的比較,但hashtables是一個淺層比較(所有hashtables被視爲等效)

現在在版本5中,數組被視爲等同,這意味着它們是一個類似於哈希表工作的淺層比較。

如果您想查看完整的詳細信息,您需要使用ilspy或.Net Reflector來反彙編DLL,並比較Microsoft.PowerShell.Commands.GroupObjectCommand類的DoGrouping方法。很難說如果它是一個錯誤,但它絕對是組對象cmdlet的突破性改變。

更新:我玩這個越多我認爲新代碼是正確的(除了顯示的名稱應該是System.Object),並且舊代碼中存在一個錯誤。看起來v4正在進行某種基於字符串的比較,即使$a.Equals([PSCustomObject]@{[email protected](1,2)})始終爲false(它們的GetHashCode方法結果不匹配),即使具有相同元素的兩個不同數組也將被組合在一起。我能得到5.0來組合類似陣列的唯一方法是使用group -Property {$_.item -join ','},它匹配4.0輸出,除了名稱是1,2而不是{1,2}。另外,如果你想使用哈希表項的鍵組合,你會使用group -Property {$_.item.somekey}(假設他們都有一個keykey的值)