Reputation: 23
This really should be more simple, but I've been getting goofy values. What I want is simple. Primarily, I want powershell to send an email if the files in a folder exceed a certain age. This part technically works. But the script has been flaky. And in reality, I'd also like the email to indicate how old the file is (although formatted in a simple xx minutes old)
Originally I was using something like this
Get-ChildItem -path $queuepath -Recurse |
Foreach-Object {
#write-host $_.fullname
$dtdiff = New-TimeSpan ($_.CreationTime) $(Get-Date)
if ($dtdiff.minutes -gt 120){ .....send an email stuff....
Trouble was, it seemed that it wasn't running that last command against all items. As in if there were files newer than 120 minutes, it would often not trigger the email, even if there were older files.. But really, I feel like it would be simpler to fix the language to simply target the oldest file in the folder to run the rest of the command against. (And produce a clean variable of "X minutes old" that I can toss into the email.
Hopefully that makes sense. And thanks for your time.
Upvotes: 0
Views: 3374
Reputation: 32200
Why not just get the list of files, sort it, grab the first, and grab the last file? Isn't that all you need to know? I'm not clear if you really need an email for each file.
$Files = @(Get-ChildItem -Path $queuepath -Recurse |
Sort-Object -Property CreationTime);
$OldestFile = $Files[0];
$NewestFile = $Files[-1];
$Now = Get-Date;
$AgeOfNewestFile = New-TimeSpan -Start ($NewestFile.CreationTime) -End $Now;
$AgeOfOldestFile = New-TimeSpan -Start ($OldestFile.CreationTime) -End $Now;
If ($AgeOfNewestFile.TotalMinutes -gt 120) {
Send-MailMessage -Body "File '$($OldestFile.FullName)' is $($AgeOfOldestFile.TotalMinutes) minutes old, and no file is newer than 120 minutes." [....];
}
You may want to include the -File
option on Get-ChildItem
if you don't want to include folders in your processing. You have the -Recurse
option specified and aren't otherwise filtering folders.
Also, you'll want to use TotalMinutes
, not Minutes
. TotalMinutes
includes the hours, days, years, etc. Minutes
is just the minutes, so it will never be greater than 59. If the file is 3 hours and 10 minutes old, Minutes
will be 10
, but TotalMinutes
will be 190
.
If you want better formatting of the message, you can use the format operator and composite formatting something like this:
$Body = "File '{0}' is {1:dd} days, {1:hh} hours, and {1:mm} minutes old." -f $OldestFile.FullName, $AgeOfOldestFile;
Or like so, if you want a more fixed string:
$Body = "File '{0}' has an age of {1:c}." -f $OldestFile.FullName, $AgeOfOldestFile;
That prints the timespan in a format of [-]d.hh:mm:ss.[fffffff].
If you want to be picky, then you get to do stuff like:
$Body = "File '{0}' is" -f $OldestFile.FullName;
If ($AgeOfOldestFile.TotalDays -gt 0) {
$Body += " {0:dd} day(s)," -f $AgeOfOldestFile;
}
And so on.
You don't have to use the format operator. You can use embedded subexpressions. I just did because it makes it a bit easier to read. Well, it is when you understand what the format operator is doing.
Upvotes: 0
Reputation: 28194
Don't send one email per file; collect all the files, filter that list down, then send the full list in one email. The following will give you a variable ($NewFiles
) which contains all of the files more than 120 minutes old and their age in minutes. You can then test to make sure it's not $null
and format it as needed for your email.
$NewFiles = get-childitem -recurse -file -path $queuepath |
Where-Object {$_.CreationTime -lt (get-date).AddMinutes(120)}|
Select-Object -Property FullName,@{name="Age";expression={New-TimeSpan -start $_.creationtime -end $(get-date) | select-object -expandproperty minutes}};
Linebreaks for better formatting here.
Upvotes: 2