Jeroen Mostert provided the crucial pointers in a comment on the question:
Unfortunately, as of PowerShell 7.0, Measure-Object
invariably converts input numbers[1] for its -Sum
, -Maximum
, -Minimum
, -Average
and -StandardDeviation
operations to [double]
(System.Double
) and reports the result as that type, which can result in loss of precision.
Your input numbers are of type [long]
, and their values exceed the highest integer that can precisely be represented in a [double]
, which is 9007199254740991
(you can calculate it with [bigint]::pow(2, 53) - 1
)
An efficient workaround is to use LINQ (System.Linq.Enumerable.Max
):
[Linq.Enumerable]::Max(
[long[]] $UserDeets.lastLogon
)
Note that the explicit [long[]]
cast is needed in order for PowerShell to be able to call the generic .Max()
method with a concrete type.
Another, less efficient, but more PowerShell-idiomatic workaround is to use sorting, similar to the OP's own answer:
# Sort the LastLogon property values, then grab the *last* one,
# which is the largest value.
($UserDeets.LastLogon | Sort-Object)[-1]
Sorting just the array of .lastLogon
values rather than the full input objects minimizes the conceptually unnecessary overhead of creating a duplicate, sorted array just so the max. value can be determined.
[1] Note that for -Min
and -Max
non-numeric inputs are accepted too, as long as they implement the System.IComparable
interface, in which case the inputs are preserved as-is and no loss of precision occurs; e.g., 'c', 'b', 'a' | Measure-Object -Minimum
and [datetime]::now, [datetime]::now.AddDays(1) | Measure-Object -Maximum
work fine, because types [string]
and [datetime]
both implement IComparable
.