【问题标题】:How to prevent PowerShell's Measure-Object cmdlet from truncating your data?如何防止 PowerShell 的 Measure-Object cmdlet 截断您的数据?
【发布时间】:2020-03-09 10:29:08
【问题描述】:

我正在尝试比较以下数据以获得最大的数字:

$UserDeets 

name                 lastLogon
----                 ---------
Frank Ti 132273694413991065
Frank Ti 132279742884182029
Frank Ti 132282196073500496
Frank Ti 132272912975826719
Frank Ti 132282144707771693
Frank Ti 132228790551703041

为此,我尝试使用内置的“测量”功能。这是我正在执行的代码

($UserDeets| measure -Property lastLogon -Maximum ).Maximum

这样的结果如下

1.322821960735E+17

正如您所看到的,尽管它正在返回正确的数据,但它正在截断最后几位数字。

有没有办法防止这种截断?

【问题讨论】:

  • 有趣——看起来Measure-Object 会产生一个Double,即使它的输入是Int64。这不仅仅是一个格式问题,因为Double 不能精确地保存Int64 的每个值。试试[System.Linq.Enumerable]::Max([long[]]($userDeets.lastLogon))(依赖 LINQ 而不是 M-O)。
  • 感谢您的回复。很高兴知道这不起作用的实际原因。我确实找到了解决办法。
  • 你可以转换你的日期时间,然后通过排序@{Name="lastLogon";Expression={[datetime]::FromFileTime($_.'lastLogon')}}得到最新的

标签: powershell measure-object


【解决方案1】:

Jeroen Mostert 在对该问题的评论中提供了关键指针:

不幸的是,从 PowerShell 7.0 开始,Measure-Object 总是将输入数字转换为-Sum-Maximum-Minimum-Average 和 @987654334 @ 操作到[double] (System.Double) 并将结果报告为该类型,这可能会导致精度损失。

您输入的数字是[long] 类型,它们的值超过了[double] 中可以精确表示的最大整数,即9007199254740991(您可以使用[bigint]::pow(2, 53) - 1 计算它)

一种有效的解决方法是使用 LINQ (System.Linq.Enumerable.Max):

[Linq.Enumerable]::Max(
  [long[]] $UserDeets.lastLogon
)

请注意,需要显式的 [long[]] 强制转换,以便 PowerShell 能够调用具有具体类型的通用 .Max() 方法。

另一个效率较低但更符合 PowerShell 惯用的解决方法是使用 排序,类似于 OP's own answer

# Sort the LastLogon property values, then grab the *last* one,
# which is the largest value.
($UserDeets.LastLogon | Sort-Object)[-1]

仅对 .lastLogon 值的数组而不是完整的输入对象进行排序,可以最大限度地减少创建重复排序数组的概念上不必要的开销。值可以确定。


[1] 请注意,对于-Min-Max,也接受非数字 输入,只要它们实现System.IComparable 接口,在这种情况下输入保持原样,不会发生精度损失;例如,'c', 'b', 'a' | Measure-Object -Minimum[datetime]::now, [datetime]::now.AddDays(1) | Measure-Object -Maximum 工作正常,因为类型 [string][datetime] 都实现了 IComparable

【讨论】:

    【解决方案2】:

    我认为您尝试通过检查多个 DC 来获取用户的最新登录信息,我通过此代码执行此操作(其中:$samacc - 当前用户,$controller - 所有 DC 主机名的列表。):

    $scriptblock={
        param($samacc,$controller)
        $result=@()
        foreach($cont in $controller){
        $RESULT=$result + (Get-ADUser -Server $cont -Identity $samacc -Properties lastlogon,whenchanged,displayname,title,company  | sort-object lastLogon -descending | select-object enabled,displayname,samaccountname,title,company, @{Name="lastLogon";Expression={[datetime]::FromFileTime($_.'lastLogon')}},whenchanged)
        }
        $result|Sort-Object -Descending -Property LastLogon|select -First 1
        }
    

    【讨论】:

      【解决方案3】:

      好的,我有一个解决方案。答案是不要使用“度量”。这是一种解决方法,但它得到了想要的答案。

      首先我对数组进行了排序:

      $UserDeets = ($UserDeets | Sort-Object -Property LastLogon)
      

      最高的对象将在数组的末尾,可以这样获得:

      $UserDeets[-1]
      

      【讨论】:

      • 比这更明显的是| Select -Last 1
      【解决方案4】:

      这对我有用。将其从 64 位浮点数转回 64 位整数。但如果是日期时间,某些数字会稍微偏离(0.000000000000005 或 5/1 万亿 % 错误),或 6 百万分之一秒(滴答声)。

      $jsontext = @'
      [ { name: 'Frank Ti', lastLogon: 132273694413991065 },
        { name: 'Frank Ti', lastLogon: 132279742884182029 },
        { name: 'Frank Ti', lastLogon: 132282196073500496 },
        { name: 'Frank Ti', lastLogon: 132272912975826719 },
        { name: 'Frank Ti', lastLogon: 132282144707771693 },
        { name: 'Frank Ti', lastLogon: 132228790551703041 },
        { name: 'Frank Ti', lastLogon: 132282196073500499 },
        { name: 'Frank Ti', lastLogon:   9007199254740991 } ]
      '@
      
      $userdeets = $jsontext | convertfrom-json
      [long]($userdeets | measure lastlogon -Maximum).maximum
      
      132282196073500496
      

      【讨论】:

      • 它适用于这个特定的值,但这很幸运。如果最大值为132282196073500497Measure-Object 将无法生成它,因为该值无法在double 中以足够的精度表示。
      • @JeroenMostert 你是对的。我想如果在转换 powershell 可以保持精度之前很久。它停留在 132282196073500496。
      • @JeroenMostert 你是怎么得到这个号码的?
      • 我从问题中提取了 132282196073500496 并添加了 1。:-) 不涉及魔法;无法正确表示小的差异这一事实是浮点如何工作的简单结果。我不知道 132282196073500496 完全可以表示,但这是一个快乐的巧合(例如,132272912975826719 不是)。下一个可以精确表示的数字是 132282196073500512。它们之间的差是 16,这当然不是 2 的幂。
      • @JeroenMostert 哦,我明白了,我以为这是一个最大值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      • 2023-04-08
      相关资源
      最近更新 更多