如何防止 PowerShell 的 Measure-Object cmdlet 截断您的数据?
How to prevent PowerShell's Measure-Object cmdlet from truncating your data?
我正在尝试比较以下数据以获得最大的数字:
$UserDeets
name lastLogon
---- ---------
Frank Ti 132273694413991065
Frank Ti 132279742884182029
Frank Ti 132282196073500496
Frank Ti 132272912975826719
Frank Ti 132282144707771693
Frank Ti 132228790551703041
为此,我尝试使用内置的 'measure' 函数。这是我正在执行的代码
($UserDeets| measure -Property lastLogon -Maximum ).Maximum
结果如下
1.322821960735E+17
如您所见,尽管它返回的是正确数据,但它截断了最后几位数字。
有没有办法防止这种截断?
好的,我有办法解决这个问题。答案是不用'measure'。这是一个解决方法,但它得到了想要的答案。
首先我对数组进行了排序:
$UserDeets = ($UserDeets | Sort-Object -Property LastLogon)
最高的对象将在数组的末尾,可以这样获得:
$UserDeets[-1]
我认为您尝试通过检查多个 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
}
这对我有用。将其从 64 位浮点数变回 64 位整数。但有些数字会略有偏差(.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
Jeroen Mostert 在对问题的评论中提供了关键指针:
不幸的是,从 PowerShell 7.0 开始,Measure-Object
invariably converts input numbers[1] for its -Sum
, -Maximum
, -Minimum
, -Average
and -StandardDeviation
operations to [double]
(System.Double
) 并将结果报告为该类型,这可能会导致精度损失。
- js2010 has reported this surprising behavior in this GitHub issue.
您输入的数字是 [long]
类型,并且它们的值超过了可以在 [double]
中精确表示的最大整数,即 9007199254740991
(您可以用[bigint]::pow(2, 53) - 1
)
一种有效的解决方法是使用 LINQ (System.Linq.Enumerable.Max
):
[Linq.Enumerable]::Max(
[long[]] $UserDeets.lastLogon
)
请注意,为了让 PowerShell 能够调用具有具体类型的通用 .Max()
方法,需要显式 [long[]]
强制转换。
另一个效率较低,但更符合 PowerShell 惯用的解决方法 是使用 排序,类似于 :
# 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
.
我正在尝试比较以下数据以获得最大的数字:
$UserDeets
name lastLogon
---- ---------
Frank Ti 132273694413991065
Frank Ti 132279742884182029
Frank Ti 132282196073500496
Frank Ti 132272912975826719
Frank Ti 132282144707771693
Frank Ti 132228790551703041
为此,我尝试使用内置的 'measure' 函数。这是我正在执行的代码
($UserDeets| measure -Property lastLogon -Maximum ).Maximum
结果如下
1.322821960735E+17
如您所见,尽管它返回的是正确数据,但它截断了最后几位数字。
有没有办法防止这种截断?
好的,我有办法解决这个问题。答案是不用'measure'。这是一个解决方法,但它得到了想要的答案。
首先我对数组进行了排序:
$UserDeets = ($UserDeets | Sort-Object -Property LastLogon)
最高的对象将在数组的末尾,可以这样获得:
$UserDeets[-1]
我认为您尝试通过检查多个 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
}
这对我有用。将其从 64 位浮点数变回 64 位整数。但有些数字会略有偏差(.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
Jeroen Mostert 在对问题的评论中提供了关键指针:
不幸的是,从 PowerShell 7.0 开始,Measure-Object
invariably converts input numbers[1] for its -Sum
, -Maximum
, -Minimum
, -Average
and -StandardDeviation
operations to [double]
(System.Double
) 并将结果报告为该类型,这可能会导致精度损失。
- js2010 has reported this surprising behavior in this GitHub issue.
您输入的数字是 [long]
类型,并且它们的值超过了可以在 [double]
中精确表示的最大整数,即 9007199254740991
(您可以用[bigint]::pow(2, 53) - 1
)
一种有效的解决方法是使用 LINQ (System.Linq.Enumerable.Max
):
[Linq.Enumerable]::Max(
[long[]] $UserDeets.lastLogon
)
请注意,为了让 PowerShell 能够调用具有具体类型的通用 .Max()
方法,需要显式 [long[]]
强制转换。
另一个效率较低,但更符合 PowerShell 惯用的解决方法 是使用 排序,类似于
# 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
.