powershellemail

Powershell send one email after checking all paths for files


I have a script which checks if there are new files in several folders and then it sends an e-mail with log file if there are new files.

$source = Get-Content "C:\AAA\source.txt"
$logDate = get-date -format yyyy-MM-dd
$logtime = get-date -format HH:mm
$log = "C:\AAA\$logdate.log"

$mailkomu = "EEE@EEE.com"
$mailod = "GGG@GGG.com"
$subject = "New files in DDD"
$zprava = "Message"

ForEach($path in $source){
    Test-path $path
    Write-Output "$logtime - $path - ok" | Out-File $log -Append 
    If ((Get-ChildItem -Path $path -Force | Measure-Object).Count -eq 0) {
        Write-Output "no files" | Out-File $log -Append
    }
    Else { 
        Write-Output "new files" | Out-File $log -Append
        $data = Get-ChildItem -Path $path -Recurse | Select-Object DirectoryName, Name
        $data | Out-File $log -Append
        Send-MailMessage -From $mailod -To $mailkomu -Subject $subject -Body $zprava -SmtpServer $SMTPServer -Attachments $log
        }
}

There are 4 different paths in source .txt but there can be more paths. The count does not matter. Checking for new files works perfectly.

The problem is, if there is a new file on e.g. the second path, it sends email immediately and does not wait for the other paths to be checked.

Example:
first path - no file - sends no email
second path - new file - sends email with log only for the first and the second path
third path - new file - sends email with log only for the first, second and the third path
fourth path - no file - sends no email

Is there a way how to make it works that it will check all paths, and if there are new files, it will send only one e-mail with log after checking all paths?


Solution

  • You just need a variable to keep track of whether any new files were found or not, and then move the Send-MailMessage call out of the loop - by waiting until after the loop is done you'll get at most 1 email, with the entire log, at once:

    $source = Get-Content "C:\AAA\source.txt"
    $logDate = get-date -format yyyy-MM-dd
    $logtime = get-date -format HH:mm
    $log = "C:\AAA\$logdate.log"
    
    $mailkomu = "EEE@EEE.com"
    $mailod = "GGG@GGG.com"
    $subject = "New files in DDD"
    $zprava = "Message"
    
    # define variable to track whether new files have been found
    $newFilesFound = $false
    
    foreach ($path in $source) {
        # start by actually acting on whether the path describes an existing item
        $folderStatus = Test-Path $path
        if (-not $folderStatus) {
            # log failure to locate source folder, then continue on to the next source folder in the loop
            Write-Output "$logtime - $path - not found" | Out-File $log -Append 
            continue
        }
    
        Write-Output "$logtime - $path - ok" | Out-File $log -Append 
    
        # path exists, let's fetch all sub-items up front
        $childItems = @(Get-ChildItem -Path $path -Force -Recurse)
    
        if ($childItems.Count -eq 0) {
            Write-Output "no files" | Out-File $log -Append
        }
        else { 
            Write-Output "new files" | Out-File $log -Append
            $data = Get-ChildItem -Path $path -Recurse | Select-Object DirectoryName, Name
            $data | Out-File $log -Append
    
            # set the indicator that files where found
            $newFilesFound = $true
        }
    }
    
    # only send email with log file if any new files were found
    if ($newFilesFound) {
        Send-MailMessage -From $mailod -To $mailkomu -Subject $subject -Body $zprava -SmtpServer $SMTPServer -Attachments $log
    }