Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to email attachments using powershell and then archive them
$verbosity_ERROR = 0;
$verbosity_WARN = 1;
$verbosity_VERBOSE = 2;
$verbosity = $verbosity_VERBOSE;
$now = Get-Date -Format s;
$read_from_folder = "\\server\volume\mail\out\user";
$file_patterns = @(
"prefix_*.csv",
"prefix_*.pdf",
"prefix_*.xls",
"prefix_*.xlsx"
);
$archive_folder = "\\server\volume\mail\archive\user";
$files = [System.Collections.ArrayList]@();
foreach($_pattern in $file_patterns) {
Get-ChildItem -Filter $_pattern -Path $read_from_folder | foreach {
$files.Add($_.FullName);
}
}
$files_count = $files.Count;
if (0 -eq $files_count) {
if ($verbosity -ge $verbosity_VERBOSE) {
Write-Output $(
"{0} INFO 1: No files found that match patterns '{1}' in folder '{2}'." -f $now,
($file_patterns -Join ", "),
$read_from_folder
);
}
} else {
$plural_s = $(If (1 -eq $files_count) {""} Else {"s"});
if ($verbosity -ge $verbosity_VERBOSE) {
Write-Output $(
"{0} INFO 2: Found {1} file{2} to send: {3}." -f $now,
$files_count,
$plural_s,
($files -Join ", ")
);
}
try {
$bm = New-Object System.Management.Automation.PSCredential(
"known-email-sender@some.where",
(ConvertTo-SecureString "known-sender-password" -AsPlainText -Force)
) -ErrorAction Stop;
#NOTE: this version of Send-MailMessage does NOT have a -ReplyTo parameter.
Send-MailMessage `
-From known-email-sender@some.where `
-Subject $("{0} reports, dd. {1}" -f $files_count, $now) `
-To recipient@some.where `
-Body $([System.String]::Concat(
"Please find attached your $($files_count) report$($plural_s): `r`n `r`n",
($files -Join ", `r`n"),
" `r`n `r`n",
"-- `r`n",
"For support and feedback, contact support@some.where. `r`n"
)) `
-Attachments $files.ToArray([System.String]) `
-Port 587 `
-SmtpServer smtp.office365.com `
-UseSsl `
-ErrorAction Stop `
-Credential $bm;
} catch {
$errmsg = $_;
Write-Output $(
"{0}: ERROR 1: {1}" -f $now,
$errmsg
);
}
if ($verbosity -ge $verbosity_VERBOSE) {
Write-Output $(
"{0} INFO 4: Moving {1} file{2} to '{3}'." -f $now,
$files_count,
$plural_s,
$archive_folder
);
}
foreach ($file in $files) {
Get-ChildItem -Path $file | Move-item -Force -Destination $archive_folder;
};
}
if ($verbosity -ge $verbosity_VERBOSE) {
Write-Output $(
"{0} INFO 5: Done." -f $now
);
}
@aeveltstra

This comment has been minimized.

Copy link
Owner Author

@aeveltstra aeveltstra commented Jul 26, 2021

We have something like this running as a scheduled task using Microsoft Windows Task Scheduler. To run it, the command in the task is powershell, and its arguments are:

    -executionPolicy Bypass -command "powershell -executionPolicy Bypass -file mailscript.ps1" 1>>stdout.log 2>>stderr.log

Wait, what? We run powershell again? So we're running it twice?

Yes!

That is necessary due to Microsoft's insistance that the -file parameter must be the last argument in the run invocation. That causes the execution to interpret the output redirects (1>>stdout and 2>>stderr) to get IGNORED. To counter that, we wrap the script file execution into another powershell invocation which uses the -command parameter and then redirects output.

@aeveltstra

This comment has been minimized.

Copy link
Owner Author

@aeveltstra aeveltstra commented Jul 26, 2021

Known issues:

  1. This script does not care about email attachment size limitations imposed by a receiving server.
  2. This script does not take input parameters from an outside invocation.
  3. The password is hardcoded into plaintext into this script. That is a security risk. Do not distribut it with the password filled in. Do not store it into code repositories with the password filled in. Adjust the script to use an environment property instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment