【问题标题】:Sort-Object not sorting correctly due to encoding issue由于编码问题,Sort-Object 无法正确排序
【发布时间】:2016-03-15 09:28:56
【问题描述】:

当我运行以下代码时:

'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 没有正确排序。它应该排在第四位。我在这里错过了什么?

更新

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

$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 可以正确排序?

【问题讨论】:

  • 我刚刚在本地运行了类似的操作,并且排序正确。你用的是什么版本的powershell?
  • PSVersion 4.0 在 Windows Server 2012 上。
  • 使用 PS 4 在我的 Server 2012 上也能正确排序。
  • 也许您的源数据有问题?也许是一些不可见的 unicode 字符?你能在十六进制编辑器中检查脚本吗?
  • Luaan,你在做点什么。当我从这里的网站复制代码时,它确实运行正常。但不是当我从源数据中复制它时,即Get-ADComputer -SearchBase 'OU=EU,DC=domain,DC=net' -Filter * -Properties OperatingSystem

标签: sorting powershell encoding active-directory powershell-4.0


【解决方案1】:

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,我必须使用一种使用“完全兼容性分解”的规范化形式,即 KC 或 KD 形式。

【讨论】:

  • 学到了一些新东西。干得好!
  • 非常感谢@JamesQMurphy,这正是我想要的。还不知道这个方法。我最后用的是$Computers | Group-Object OperatingSystem | Select-Object @{N='OS';E={$_.Name.ToString().Normalize([Text.NormalizationForm]::FormKC)}},Count | Sort-Object OS
【解决方案2】:

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

查看 Ansi 代码,您在违规项目上看到的空间是 160,高于 32 的自然空间。

话虽如此,您只需在自定义属性上Sort 即可获得您正在寻找的结果。

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

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

【讨论】:

  • 感谢 Matt 的解决方法。最后,我认为@JamesQMurphy 在这种情况下他的答案更好,所以我使用了那个。
【解决方案3】:

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

搜索“PowerShell 自定义排序”导致我在此页面上找到答案: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'

【讨论】:

  • 感谢 Kory 的排序提示,非常感谢。
【解决方案4】:

-Properties 参数不只显示指定的属性,而是将它们添加到标准集中。所以运行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,你会没事的。

【讨论】:

  • 谢谢亚当,我知道这一点。我已经更新了 OP 以反映完整的代码,以便您可以更好地看到它。我很抱歉造成混乱,但它不起作用。在Sort-Object 可以正确处理之前,应该对字符串进行一些更改..
猜你喜欢
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 1970-01-01
相关资源
最近更新 更多