Powershell 5 中的哪些变化改变了块大括号的含义 [英] What change in Powershell 5 changes meaning of block curly brackets

查看:46
本文介绍了Powershell 5 中的哪些变化改变了块大括号的含义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们最近将构建服务器上的 Powershell 版本从 4.0 更新到了 5.0.这一变化导致我们的一个构建脚本以一种意想不到的方式开始失败.

We recently updated the Powershell version on our build servers from 4.0 to 5.0. This change caused one of our build scripts to start failing in an unexpected way.

该代码用于确定我们的产品中应包含哪些用户指南.该代码处理一个 xml 节点列表,这些节点描述了所有可用文档的版本和文化.我们按文档标题和文化分组,然后选择最合适的版本.

The code is used to determine which user guides should be included in our product. The code processes a list of xml nodes that describe all available documents with version and culture. We group by document title and culture and then select the most fitting version.

$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 中,此代码将所有文档分组在一个列表中,然后从该列表中选择最合适的版本.鉴于我们有多种语言的文档,这意味着只会提供最合适版本的语言.

In Powershell 4 this code correctly sorts the documents by title and culture and then selects the most suitable version. In Powershell 5 this code groups all documents in a single list and then selected the most suitable version from that list. Given that we have documents in multiple languages this means that only the language with the most suitable version will be present.

问题已通过更改修复

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

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

现在我明白根据文档,第一个语法在技术上是不正确的,因为 Group-Object 需要一组属性名称来分组,但是在 Powershell 4 中,代码确实返回了所需的结果.

Now I understand that the first syntax is not technically correct according to the documentation because Group-Object expects an array of property names to group on, however in Powershell 4 the code did return the desired results.

现在的问题是 Powershell 5 中发生了什么变化,原始代码在 Powershell 4 中有效,但在 Powershell 5 中失败.

The question now is what changed in Powershell 5 that the original code worked in Powershell 4 but failed in Powershell 5.

推荐答案

Group-Object cmdlet 的语法看起来没有改变,因为下面显示了相同的定义(以及方法所在的 DLL定义)两个版本:

It doesn't look like the syntax of the Group-Object cmdlet was changed, as the following shows the same definition (along with the DLL where the method is defined) for both versions:

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 不同.例如:

But as PetSerAL mentioned in a comment it looks like the 5.0 DLL handles arrays differently than 4.0. For example:

$a=[PSCustomObject]@{item=@(1,2)}   #Object with an array for the value of the item property
$b=[PSCustomObject]@{item=@(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]@{item=@{key='value'}}   #Similar but this time the item value is a hashtable
$d=[PSCustomObject]@{item=@{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 版中,数组值被视为单独的组,但哈希表被视为相等的组.这意味着数组有深度比较,但哈希表是浅比较(所有哈希表都被视为等效)

Note that in version 4 the array values were treated as separate groups, but the hash tables are treated as equal groups. That means arrays had a deep compare, but hashtables were a shallow compare (all hashtables are treated as equivalent)

现在在第 5 版中,数组被视为等效的,这意味着它们是类似于哈希表工作方式的浅比较.

Now in version 5 the arrays are treated as equivalent, meaning they are a shallow compare similar to how the hashtables worked.

如果您想查看完整的详细信息,您需要使用 ilspy 或 .Net Reflector 来反汇编 DLL 并比较 Microsoft.PowerShell.Commands.GroupObjectCommand 类的 DoGrouping 方法.很难说这是否是一个错误,但对于 group-object cmdlet 来说,这绝对是一个突破性的变化.

If you want to see the full details you would need to use ilspy or .Net Reflector to disassemble the DLL and compare the DoGrouping method of the Microsoft.PowerShell.Commands.GroupObjectCommand class. Hard to say if it is a bug or not, but it definitely is a breaking change for the group-object cmdlet.

更新:我玩得越多,我就越认为新代码是正确的(除了显示的名称应该是 System.Object)并且旧代码中存在一个错误.似乎 v4 正在进行某种基于字符串的比较,因为即使 $a.Equals([PSCustomObject]@{item=@(1,2)}) 始终为假(它们的 GetHashCode 方法结果不匹配).我可以让 5.0 对类似数组进行分组的唯一方法是使用 group -Property {$_.item -join ','},它与 4.0 输出匹配,但名称是 1,2 而不是{1, 2}.此外,如果您想使用哈希表项的键进行分组,您将使用 group -Property {$_.item.somekey} (假设它们都有一个 somekey 的值)

Update: the more I play with this the more I think the new code is correct (except the displayed name should just be System.Object) and there was a bug in the old code. It seems like v4 was doing some sort of string based comparison, as even two different arrays with the same elements would be grouped together, even though $a.Equals([PSCustomObject]@{item=@(1,2)}) is always false (their GetHashCode method results don't match). The only way I could get 5.0 to group similar arrays was using group -Property {$_.item -join ','}, which matched the 4.0 output except the name was then 1,2 instead of {1, 2}. Also if you want to group using a key of a hashtable item you would use group -Property {$_.item.somekey} (assuming they all have a value for somekey)

这篇关于Powershell 5 中的哪些变化改变了块大括号的含义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆