cancel
Showing results for 
Search instead for 
Did you mean: 
Create Post

Advanced File Age Monitor with PowerShell

Jump to solution

Hi,


I need to monitor the age of file in a folder. I can not use the default File Age monitor because it does not accept a wildcard for filename.

The files that are in the folder have different names, hence the need to use another File Age monitoring approach.


I've found a PowerShell script online that does the trick but I am having difficulties getting it to work in SAM. It could be that I don't fully understand what SAM expects as an output.

Hopefully someone here can help so that we all can benefit from it. I know a lot of people have requested the ability to monitor File Age when file does not have a set name.


Here's the PowerShell script:


$fullPath = "C:\hp\hpsmh\certs"
$numdays = 3
$numhours = 10
$nummins = 5
function ShowOldFiles($path, $days, $hours, $mins)
{
$files = @(get-childitem $path -include *.* -recurse | where {($_.LastWriteTime -lt (Get-Date).AddDays(-$days).AddHours(-$hours).AddMinutes(-$mins)) -and
($_.psIsContainer -eq $false)})
if ($files -ne $NULL)
{
for ($idx = 0; $idx -lt $files.Length; $idx++)
{
$file = $files[$idx]
write-host ("Old: " + $file.Name) -Fore Red
}
}
}
ShowOldFiles $fullPath $numdays $numhours $nummins

Attached screenshots show a test script and the expected output (file name in red). The other screenshot shows the error displayed in SAM when performing a test.

Are there any SAM/PowerShell gurus around that ould modify the script so that it works with SAM?

1 Solution
Level 12

SAM is expecting 2 lines to come back, one a message (optional), and another a statistic.  Your output doesn't match the format that SAM is after.  I'd do the following:

$path = 'c:\temp'

$stats = 0

$msg = ''

$days = 3

$hours = 10

$mins = 5

$files = @(Get-ChildItem -Recurse -Path $path -Include '*.*' | ?{ $_.LastWriteTime -lt (Get-Date).AddDays(-$days).AddHours(-$hours).AddMinutes(-$mins) -and $_.psIsContainer -eq $false})

if ($files -ne $null) {

  $f_names = [System.String]::Join('|',$files)

  $msg = 'Message: ' + $f_names

  $stats = $files.Count

} else {

  $msg = 'Message: 0 files exceed defined age'

}

Write-Host $msg

Write-Host "Statistic: $stats"

WIth this, it'll output the file names in the Message, and the file count that exceeds the age will be a statistic, and you can monitor/alert based on that value. One thing to be careful of is the length that the message will get, depending on the number of files in the path.

Edit: Corrected a 'typo' on line 22 which originally said 'Statistics' rather than the correct verbiage 'Statistic', and corrected variables $minutes to $mins

View solution in original post

42 Replies
Level 8

How should the code look like, if i dont want subfolders to be included in the code?

0 Kudos
Level 8

No, I choose to inherit from node, which has admin rights on the server and can access the path if I RDP to the server using those credentials.

0 Kudos
Level 8

Like many who have posted here, I'm also facing similar issue. This isn't working for me if I change the path from C:temp as in the script to something that I want to monitor. It keeps saying "0 files exceed defined age" even though there are more than 1000 files in it.

Basically I'm trying to monitor mail queue in C:\inetpub\mailroot\Queue path, to alert if us if a mail is stuck there for more than 30 minutes.

$path = C:\inetpub\mailroot\Queue

$stats = 0

$msg = ''

$days = 0

$hours = 0

$mins = 30

$files = @(Get-ChildItem -Recurse -Path $path -Include '*.*' | ?{ $_.LastWriteTime -lt (Get-Date).AddDays(-$days).AddHours(-$hours).AddMinutes(-$mins) -and $_.psIsContainer -eq $false})

if ($files -ne $null) {

  #$f_names = [System.String]::Join('|',$files)

  #$msg = 'Message: ' + $f_names

  $stats = $files.Count

} else {

  $msg = 'Message: 0 files exceed defined age'

}

Write-Host $msg

Write-Host "Statistic: $stats"

Note: I have commented file names portion as I don't need to know the file names.

0 Kudos

Silly questions (maybe) - are you running it as a particular user? Do you have the impersonate checkbox checked? If so, does that user have access to that path?

0 Kudos
Level 7

Any suggestion for getting the $f_names to only include the file names and not the full UNC path? My $msg output for a sample file is:

\\servername.domain.local\subfolder\subfolder2\subfolder3\test.txt

0 Kudos

You can change line 13 to read:

  $f_names = [System.String]::Join('|',$files.Name) 

This should return just the file names.

0 Kudos

What I meant to say was: thank you, that works perfectly!

Do you have any advice for passing the results of that script into the Alert i set up to monitor the application?

0 Kudos

You can use the following variables to output the useful data:

${N=SwisEntity;M=ComponentAlert.StatisticData}

${N=SwisEntity;M=ComponentAlert.ComponentMessage}

The "StatisticData" will output numerical value, which will be the number of files, and "ComponentMessage" will be the list of the files, separated by "|" character.

0 Kudos

Hi Jonathan,

I'll start off by stating that I really don't know anything about scripting, so any help you maybe able to provide would be greatly appreciated! I believe the script provided above is along the lines of what I'm looking for. What I need to know is, what exactly do I need to modify in order to order to have poll for NEW ".OLD" files in a specific folder.

Any help would be greatly appreciated!

0 Kudos

The -include '*.*' can be changed to -include '*.OLD'

0 Kudos

So this is the output that I get after running the script with the ".old" change.

Output: ==============================================

Message: 0 files exceed defined age

Statistic: 0

Errors: ==============================================

Get-ChildItem : Cannot find path '\\FQDNservername\d$\SubFolder' because it does not exist.

At line:9 char:12

+ $files = @(Get-ChildItem -Recurse -Path $path -Include '*.old' | ?{ $_.LastWri ...

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : ObjectNotFound: (\\FQDNservername\d$\SubFolder:String) [Get-ChildItem], ItemNotFoundException

+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Also tried using the IP instead of server name. Any thoughts? The folder does exist, and I did verify that I am testing on the correct server. Unlike jokautzman's situation (sept 30th posting), I'm using the correct credentials.

Any suggestions would be great.

0 Kudos

Drive letters with $ after are usually admin type shares that have restricted access just to administrators.  Is the account you're using an admin on the remote server? Can you create a new share pointed straight to "SubFolder" and see if that works? I'm always hesitant to use the drive shares, especially as it introduces powershell variable delimiters into the code, which could cause other issues.

Another option is that sometimes PowerShell doesn't load the providers, so it doesn't know how to handle the path names.  Try adding Set-Location C: above the Get-ChildItem line.  There are some details about it here with a different solution as well.

0 Kudos

Alright, I tried a good combination of these yesterday with no success. The $ symbol was actually a mistake. The folder is located on the D drive. So I've now changed that to "D:". When running the script via the "GET SCRIPT OUTPUT" button on Solarwinds when creating a template, the output returned is 

pastedImage_3.png

Just to verify.... This should be looking for anything that is a minute old right? I wouldn't be surprised if I was totally wrong. haha That would be why I'm searching for assistance

Am I doing anything else wrong that would cause the script out put to return with "Not Defined"?

Thank you so much for the input and the link!

0 Kudos

Is the share actually created as "D:" or just "D"? I'm not sure you can create a windows share with : in them.  What I'd suggest is trying to make a new share on the server such as directly to the subfolder with the files, and use that share name.  Make sure to grant the account that you're using to access with the necessary rights.

I would also set $days and $hours to 0, instead of a blank value, otherwise you might cause an issue with the powershell processor.

0 Kudos

Kudos for getting back to me so quickly Jonathan!

I will give the change a shot and see how it goes!

0 Kudos

Hi there,

What evidence do you have and can use, in order to determine whether the file is new or not?

If it is the timestamp, what would the time difference be and is it constant?

0 Kudos

Wow! You guys are awesome for the quick replies! Kudos!

I would think the time stamp would be the best bet. It is pretty constant except in the middle of the night... The files will have a gap of an hour max! Usually they're updated every few minutes. So, if there wasn't a new .old file in an hour, I would like for it to alert.

***EDIT***

Deltona,

We could also poll for any ".queue" files. If there are more then 2 present we could alert on that as well if that makes it any easier. Being that those are the files being converted into .old files and should not accumulate.

0 Kudos

The alert results are printing the variables as plain text instead of interpreting them.

pastedImage_0.png

0 Kudos

Which version of SAM are you using? They changed the variable format relatively recently.  The above format is the new style, but the old alerting style uses much shorter styles.  Do you manage your alerts via the SolarWinds web console?  If so, go to the alert you're trying to edit, go to the trigger actions, select your email and in the "Message" section click on the "Insert Variable" button.  The top button will put the variables in the subject line, the bottom will put it in the body.

2016-10-13 10_28_40-Edit Alert - _ADConnect - Sync Time_.png

Change the drop down on the left for "Show variables for" to "Component" and take a look at some of the values there and test.  I may have provided the wrong one, or for some reason copy/paste didn't work.  For the two above, I used "Statistic Data (Component Alerting Properties)" and "Component Message (Component Alerting Properties)".  Click the "Insert Variable" button, and move it to where you want it.  You can insert multiple variables at once, then cut/move them in the actual message.

0 Kudos

Fantastic, I'll give that a try.

0 Kudos