Checking multiple files ...

by Lahru at 2012-11-19 11:26:40

Is there a way to do this?
For each/all files in a directory.
Subtract the file’s modified time from the current time
If the time frame for ANY file is outside of a specified timeframe
Complete an action?

My purpose in this is to check up on a proprietary service that sometimes hangs but doesn’t stop.
If I could script the logic outlined above, then finding a file that is so many minutes old would indicate that the service isn’t working and I’d like to then trigger an alert.
by DonJ at 2012-11-19 11:32:26
Yeah, pretty easily.

Get-ChildItem -path \whatever | ForEach {


Inside that ForEach block, you’d put your calculation and use an If construct to check your timeframe. Something like $.LastWriteTime - $.CreationTime would be the calculation.

In v3, add the -File parameter to Get-ChildItem so that it doesn’t return directories, if there are subfolders in there. Add -recurse to recurse files in subfolders.
by Lahru at 2012-11-19 12:25:52
OK, awesome, so that gets me here: $files = get-childitem -path \any\where* -include *.pdf, *.tif, *.jpg
Foreach ($file in $files)
$time = ((get-date) - $file.LastWriteTime).Totalminutes
IF($time -gt 2)
Write-Host "$file is $time minutes old."
What I’d like to do is send an email rather than write-host and I can do this with the send-MailMessage Cmdlet, but I don’t need a message per file.
So is there a way to get only 1 ACTION if 2 files return $True?

I could write a new-item to a specific directory and then check that directory sending a message if a Trigger File exists, but I think that is getting too complicated.
by DonJ at 2012-11-19 12:39:03
Write-Host is evil ;).

Just accumulate your message in a variable:

$message = ‘’


$message += "$file is $time minutes old"

You can pass that to Send-MailMessage at the end of your script. Is $message -eq ‘’ at the end, then don’t send anything. I could probably turn this into a one-liner, even.

$mailbody = Dir \any\where* -include .txt,.pdf | where { ((get-date) - $.lastwritetime).totalminutes -gt 2 } | Select @{n=‘File’;e={$.name}},@{n=‘Minutes Old’;e={((get-date) - $.lastwritetime).totalminutes}}

Then just use Send-MailMessage and $mailbody. Shame Send-Mail doesn’t accept pipeline input. Coulda made it a true one-liner.
by Lahru at 2012-11-20 08:18:35
Ok I am not completely certain what is happening in your one liner. But I need to refine my trigger for the action regardless of the action.

I want to send an alert or complete an action such as restarting a service,
but I don’t want to send out 50 messages (1 for each file) & I don’t want to restart a service 50 times either.
How would I get 1 single action out of this?
So in other words; regardless of whether I get 1 old file or 100 I want only 1 alert. How can I do that?

my attempts to run the one-liner against a directory I know has files that match the "too old" parmeters I get this]Send-MailMessage : Cannot validate argument on parameter 'Body'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.[/powershell]
by DonJ at 2012-11-20 08:26:34

$mailbody = Dir \any\where* -include .txt,.pdf | where { ((get-date) - $
.lastwritetime).totalminutes -gt 2 } | Select @{n=‘File’;e={$.name}},@{n=‘Minutes Old’;e={((get-date) - $.lastwritetime).totalminutes}}

if ($mailbody) { Send-MailMessage -To x -From x -Body $mailbody }

The one-liner is just doing what your script was doing. If you prefer that:

$files = get-childitem -path \any\where* -include *.pdf, *.tif, *.jpg
$message = ‘’
Foreach ($file in $files)
$time = ((get-date) - $file.LastWriteTime).Totalminutes
IF($time -gt 2)
$message += "$file is $time minutes old.`n"
if ($message -ne ‘’) { Send-MailMessage -To x -From x -Body $message }

You got the error because, I suspect, you tacked Send-MailMessage onto the end of what I gave you. Can’t do that, because nothing in it accepts pipeline input.