由于编码问题,排序对象未正确排序

Sort-Object not sorting correctly due to encoding issue

当我运行以下代码时:

'Windows Embedded Standard',
'Windows 7 Enterprise',
'Windows XP Professional',
'Windows Server 2003',
'Windows 7 Entreprise',
'',
'Windows 7 Professionnel',
'Windows 7 Professional',
'Windows 10 Enterprise',
'Windows Server 2008 R2 Standard',
'Windows Server 2012 Standard',
'Windows Server 2012 R2 Standard',
'unknown',
'Windows Server 2008 R2 Enterprise' | Sort-Object

排序如下:

unknown
Windows 10 Enterprise
Windows 7 Enterprise
Windows 7 Professional
Windows 7 Professionnel
Windows Embedded Standard
Windows Server 2003
Windows Server 2008 R2 Enterprise
Windows Server 2008 R2 Standard
Windows Server 2012 R2 Standard
Windows Server 2012 Standard
Windows XP Professional
Windows 7 Entreprise

我不明白为什么最后一个条目 Windows 7 Entreprise 没有正确排序。它应该排在第四位。我在这里错过了什么?

更新

感谢评论,很明显源数据似乎是问题所在:

$Computers = Get-ADComputer -SearchBase 'OU=EU,DC=domain,DC=net' -Filter * -Properties OperatingSystem
$Computers | Group-Object OperatingSystem | Sort-Object Name | Select-Object Count, Name | Format-Table -AutoSize

ANSI 值:

$Computers | Group-Object OperatingSystem | ForEach-Object{$_.Name;[int[]][char[]]$_.Name -join "|"}
Windows Server 2008 R2 Standard
87|105|110|100|111|119|115|32|83|101|114|118|101|114|32|50|48|48|56|32|82|50|32|83|116|97|110|100|97|114|100
Windows Server 2003
87|105|110|100|111|119|115|32|83|101|114|118|101|114|32|50|48|48|51
Windows Server 2012 Standard
87|105|110|100|111|119|115|32|83|101|114|118|101|114|32|50|48|49|50|32|83|116|97|110|100|97|114|100


Windows Server 2012 R2 Standard
87|105|110|100|111|119|115|32|83|101|114|118|101|114|32|50|48|49|50|32|82|50|32|83|116|97|110|100|97|114|100
unknown
117|110|107|110|111|119|110
Windows Server 2008 R2 Enterprise
87|105|110|100|111|119|115|32|83|101|114|118|101|114|32|50|48|48|56|32|82|50|32|69|110|116|101|114|112|114|105|115|101
Windows 7 Enterprise
87|105|110|100|111|119|115|32|55|32|69|110|116|101|114|112|114|105|115|101
Windows 7 Entreprise
87|105|110|100|111|119|115|160|55|32|69|110|116|114|101|112|114|105|115|101
Windows 7 Professionnel
87|105|110|100|111|119|115|32|55|32|80|114|111|102|101|115|115|105|111|110|110|101|108
Windows XP Professional
87|105|110|100|111|119|115|32|88|80|32|80|114|111|102|101|115|115|105|111|110|97|108
Windows 7 Professional
87|105|110|100|111|119|115|32|55|32|80|114|111|102|101|115|115|105|111|110|97|108
Windows 10 Enterprise
87|105|110|100|111|119|115|32|49|48|32|69|110|116|101|114|112|114|105|115|101
Windows Embedded Standard
87|105|110|100|111|119|115|32|69|109|98|101|100|100|101|100|32|83|116|97|110|100|97|114|100

有没有办法对它进行不同的编码,以便 PowerShell 可以对其进行正确排序?

-Properties 参数不只显示指定的属性,而是将它们添加到标准集中。所以 运行ning Get-ADComputer -Filter "name -like '*'" -Properties OperatingSystem 结果我不只得到 OperatingSystem 属性,而是所有这些:DistinguishedName, DNSHostName, Enabled, Name, ObjectClass, ObjectGUID, OperatingSystem, SamAccountName, SID, UserPrincipalName.

现在当你 运行 像这样: Get-ADComputer -Filter "name -like '*'" -Properties OperatingSystem | sort | select OperatingSystem 这意味着您按 DistinguishedName 排序,然后选择了 OperatingSystem。

使用| Sort-Object OperatingSystem,你会没事的。

所以我有一个解决这个问题的方法,但它比我想要的更骇人听闻。您的环境中有法语 OSes。根据您的某些系统的拼写,这是显而易见的。根据您对这些数据的处理方式,如果您需要按 OS 分组,则无论如何您都必须对其进行处理,因为语言之间的拼写不同。

查看 Ansi 代码,您在有问题的项目上看到的 space 是 160,高于自然的 space,即 32。

话虽如此,您只需 Sort 自定义 属性 即可获得所需的结果。

| Sort-Object {$_ -replace [char]160," "}

即使字符在屏幕上正确显示,也不会按照您想要的方式排序。我 认为 鉴于提供的数据,此解决方案是必需的。我还没有任何提供多语言环境和其他想法的经验。

String.Normalize() 函数与规范化形式 KC 或 KD (documented here) 结合使用:

$Computers = Get-ADComputer -SearchBase 'OU=EU,DC=domain,DC=net' -Filter * -Properties OperatingSystem
$OSList = $Computers | Select-Object -ExpandProperty OperatingSystem | ForEach-Object {
    $_.ToString().Normalize([Text.NormalizationForm]::FormKC)
}

请注意,Normalize 函数将删除变音符号,例如重音符号和重音符号。例如,á 将成为 a。为了将字符 160 转换为字符 32,我不得不使用使用 "full compatibility decomposition," 的规范化形式之一,即 KC 或 KD 形式。

有趣的问题,用数字对字符串进行排序总是很棘手,因为 ASCII/ordinal 值的“1”小于“7”,因此它将比较 "Windows 10" 小于 "Windows 7".

搜索 "PowerShell custom sorting" 使我在此页面上找到答案:custom sorting in powershell

我以这种方法为基础编写了以下解决方案。

代码

$items = @(
'Windows Embedded Standard',
'Windows 7 Enterprise',
'Windows XP Professional',
'Windows Server 2003',
'Windows 7 Entreprise',
'',
'Windows 7 Professionnel',
'Windows 7 Professional',
'Windows 10 Enterprise',
'Windows Server 2008 R2 Standard',
'Windows Server 2012 Standard',
'Windows Server 2012 R2 Standard',
'unknown',
'Windows Server 2008 R2 Enterprise')

# Define our search criteria
# match non-digits
$part1 = { if ($_ -match '(\D+)') { $matches[1] } }
# after part 1, match digits and cast to int so sorting works by number/value
$part2 = { if ($_ -match '\D+(\d+)') { [int]$matches[1] } }
# rest of string after part 2
$part3 = { if ($_ -match '\D+\d+(.*)') { $matches[1] } }

Write-Output "`nTest of our parts and how they parse a string."
# write values out surrounded by single quotes so we see exactly what is returned
'Windows 10 Enterprise' | % $part1 | % {Write-Output $("'" + $_ + "'")}
'Windows 10 Enterprise' | % $part2 | % {Write-Output $("'" + $_ + "'")}
'Windows 10 Enterprise' | % $part3 | % {Write-Output $("'" + $_ + "'")}

Write-Output "`nSorted by string (where 1 is less than 7, even if number is 10"
$items | Sort-Object | % {Write-Output $("'" + $_ + "'")}

Write-Output "`nSorted using our custom parsing rules!!!"
# write values out surrounded by single quotes so we see exactly what is returned
$items | Sort-Object $part1, $part2, $part3 | % {Write-Output $("'" + $_ + "'")}

输出:

Test of our parts and how they parse a string.
'Windows '
'10'
' Enterprise'

Sorted by string (where 1 is less than 7, even if number is 10
''
'unknown'
'Windows 10 Enterprise'
'Windows 7 Enterprise'
'Windows 7 Entreprise'
'Windows 7 Professional'
'Windows 7 Professionnel'
'Windows Embedded Standard'
'Windows Server 2003'
'Windows Server 2008 R2 Enterprise'
'Windows Server 2008 R2 Standard'
'Windows Server 2012 R2 Standard'
'Windows Server 2012 Standard'
'Windows XP Professional'

Sorted using our custom parsing rules!!!
''
'unknown'
'Windows 7 Enterprise'
'Windows 7 Entreprise'
'Windows 7 Professional'
'Windows 7 Professionnel'
'Windows 10 Enterprise'
'Windows Embedded Standard'
'Windows Server 2003'
'Windows Server 2008 R2 Enterprise'
'Windows Server 2008 R2 Standard'
'Windows Server 2012 R2 Standard'
'Windows Server 2012 Standard'
'Windows XP Professional'