2016-07-26 24 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的值)