Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aeveltstra/52f697fa88883eff3460b93684d2ae28 to your computer and use it in GitHub Desktop.
Save aeveltstra/52f697fa88883eff3460b93684d2ae28 to your computer and use it in GitHub Desktop.
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
Copy link
Author

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
Copy link
Author

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