Today I needed to find the latest date/time value from a set of values and stumbled upon an issue with the standard measure-object
cmdlet failing for DateTime values (click the link to vote for this to be fixed by the way).
Obviously, as a true PowerSheller, whenever I come across a limitation like that I simply use the extensibility of PowerShell to get through. Here’s the Measure-Latest
function which I created. It takes the values from the pipeline and outputs the latest of them (or $null
if the pipeline was empty or only had $null
values):
# get a set of DateTime values from the pipeline # filter out $nulls and produce the latest of them # (c) Dmitry Sotnikov function Measure-Latest { BEGIN { $latest = $null } PROCESS { if (($_ -ne $null) -and (($latest -eq $null) -or ($_ -gt $latest))) { $latest = $_ } } END { $latest } }
Usage is pretty simple:
# when was the last time something was modified in the current folder? dir | foreach { $_.LastWriteTime } | Measure-Latest
Enjoy!
Tags: Examples, KB, Knowledge Base, Known Issues, PowerShell
I like it, but this is useful for more than datetime objects. This can be used for any object where -gt works. I’m thinking of stealing this but calling it Get-Max. 🙂
Be my guest 🙂
This is a nice example, but would this not do the same thing:
dir | Sort-Object LastWriteTime | Select-Object -Last 1
It would, but if I remember what I was being told in my computer science classes loooong time ago: sorting was a more resource expensive operation than just determining the maximum value. To find max you just scan the collection once. Sorting requires going through the collection more than that.
With that said, yes, sorting and picking the last value should also give you the latest one.
Good point. You are correct that sorting is more expensive. I was just in command line mode. 🙂
Completely redundant since it has already been pointed out that sorting is more expensive, but here is an example. This is looking at the windows dir on my laptop:
$dirOnly = Measure-Command {dir -rec}
$dirSorting = Measure-Command {dir -rec | Sort-Object LastWriteTime | Select-Object -Last 1}
$dirMax = Measure-Command {dir -rec | foreach { $_.LastWriteTime } | Measure-Latest}
$dirOnly.TotalSeconds
10.4870283
$dirMax.TotalSeconds
15.1897679
$dirSorting.TotalSeconds
19.300323
Yep, and the bigger the dataset the bigger the difference will be.
Forgive me if this is too elementary a question, but how would I get this value exported in a csv along with other user account values such as pwdlastset, creationdate, etc.?
Thanks!
Jim
Your blog is an excellent resource, Dmitry! Forgive me if I haven’t searched well enough for the answer.
Sorry… (again!) my comment above was with regard to the last true logon post which uses this function (“Finding the latest logon time « Dmitry’s PowerBlog: PowerShell and beyond”). How can you feed the “Measure-Latest” value of the latest logon query into a spreadsheet with rest of the other get-qaduser information?
One cool thing I found out recently is the ability in PowerShell to use a variable in place of an explicit property name. I’ve refactored the example given here to look a bit more like Measure-Object.
function Measure-Latest([String] $Property = $null, [Switch] $Earliest) {
BEGIN { $value = $null }
PROCESS {
if($Property){
$TestObject = $_.$Property
}else{
$TestObject = $_
}
if($Earliest){
$Logic = $TestObject -lt $value
}else
{
$Logic = $TestObject -gt $value
}
if (($TestObject -ne $null) -and (($value -eq $null) -or ($Logic))) {
$value = $TestObject
}
}
END { $value }
}
“Earliest”
dir | measure-Latest LastWriteTime -earliest
“Latest”
dir | measure-Latest LastWriteTime
This looks very cool! Thanks!
Hey mate, I recently used (slightly modified) this script in order to find the most recent folder in a given share. I’m quite new to PS.
cd C:\SD\projects\folder\MoveProject\Archive
dir | foreach { $_.LastWriteTime } | Measure-Latest
write-host $latest
Here’s how I figured out how to incorporate it. This script displays the latest, I think this is how it’s done, it works, anyway.
Now, to actually GET files FROM that latest folder and copy them locally…
🙂
Thanks for posting this, Donald! Glad that the function was helpful.
when i run this I don’t get any results back. I can see it hitting each domain controller but nothing comes back. Do I have to wrap this around some other code to get it to work.
Get-QADComputer -ComputerRole DomainController | foreach {
Write-Host $_.Name
(Get-QADUser -Service $_.Name -SamAccountName username).LastLogon.Value } |
Measure-Latest
I am not with the team anymore, so cannot say for sure, but I would try to remove .Value – they could have made LastLogon to just work without it.
If that does not help, you can also contact the team at the PowerShell and AD forum at http://powergui.org
Dmitry
I know this is very old post, I learned a lots from you, including your ‘Pro Windows PowerShell’ book, so I would like your comment.
I think issue that you experienced with standard measure-object cmdlet failing for DateTime values is related to object being passed is the String and measure-object does string ordering. If you pass DateTime type then it looks that works properly ( got same results as your example):
(dir c:\temp | foreach { [datetime []] $_.LastWriteTime} | Measure-Object -Maximum).Maximum