Comment by connann2 on July 15, 2020 at https://tech.wandersick.com/2016/07/powershell-automation-of-journal.html?showComment=1594815180927#c3772578974826337608
# To simplify run script from Task Sheduler with Program/script: powershell.exe and Argument: D:\Scripts\ws_email_archiving.ps1 or your path | |
# And "Run with highest privileges" | |
# | |
# If script is runed manual it must be "Run as Administrator" | |
# | |
# This mod of script assume exportin every 10 days - on 1st, 11 and 21 date every month | |
# | |
# I dont touch original notes! Just add some my. | |
# Add "en-US" localization because New-MailboxExportRequest -ContentFilter cant work with dates with other localizations | |
[System.Reflection.Assembly]::LoadWithPartialName("System.Threading") | |
[System.Reflection.Assembly]::LoadWithPartialName("System.Globalization") | |
[System.Threading.Thread]::CurrentThread.CurrentCulture = [System.Globalization.CultureInfo]::CreateSpecificCulture("en-US") | |
[System.Threading.Thread]::CurrentThread.CurrentCulture = "en-US" | |
Add-PSSnapin *exchange* | |
# WS Email Archiving - Journal Mailbox Archiving PowerShell Script for Exchange 2013 | |
# Written by wandersick (https://wandersick.blogspot.com/2016/07/powershell-automation-of-journal.html) | |
# Version: 1.2 (20171022) | |
# The default parameters of this script assume monthly exporting. See above URL for more information. | |
# The [Output Examples] in the comment sections below assume: | |
# Date of script execution: 02 Feburary 2016 | |
# Date of archive period: Between 01 and 31 January 2016 (previous month) | |
# ---------------------------------------- | |
# 1. DEFINING MAIN VARIABLES | |
# ---------------------------------------- | |
# Specify name of a journal mailbox where this script will process | |
# [Output Examples] | |
# journalMailboxName = "messagejournal" | |
$journalMailboxName = "Specify a mailbox name here" | |
# Period of messages to be exported to PST by New-MailboxExportRequest cmdlet | |
# Note: Previous month is assumed for the default parameters | |
# Get last day of last month, start day of this month (not converted to string yet) | |
# [Output Examples] | |
# endDate = Monday, February 1, 2016 12:00:00 AM | |
# startDate = Friday, Jaunuary 1, 2016 12:00:00 AM | |
#$endDate = Get-Date -Day 1 "00:00:00" | |
#$startDate = $endDate.AddMonths(-1) | |
#$endDate = Get-Date -Day 11 "00:00:00" | |
#$startDate = Get-Date -Day 1 "00:00:00" | |
#$endDate = (Get-Date "00:00:00").AddDays(-10) | |
# To archive 10 day before today. Because Search-Mailbox -SearchQuery $searchDateRange | |
If (([System.DateTime]::Now).IsDaylightSavingTime()) { | |
$endDate = (Get-Date ([TimeZoneInfo]::Local).BaseUtcOffset.ToString()).AddDays(-10).AddHours(1).AddMinutes(1) | |
} Else { | |
$endDate = (Get-Date ([TimeZoneInfo]::Local).BaseUtcOffset.ToString()).AddDays(-10).AddMinutes(1) | |
} | |
$startDate = $endDate.AddMonths(-1) | |
# (continued) | |
# Get last day of last month in "yyyy_MM_dd" string | |
# Name PST file using: specified string + last day of last month | |
# Set file path from it for storing the first copy of PST file | |
# [Output Examples] | |
# archiveDate = 2016_01_31 | |
# archiveFile = archive 2016_01_31.pst | |
# archiveFileDir = \\localhost\e$\Archive_PST\ | |
# archiveFilePath = \\localhost\e$\Archive_PST\archive 2016_01_31.pst | |
#$archiveDate = (Get-Date).AddDays(- (Get-Date).Day).ToString('yyyy_MM_dd') | |
$archiveDate = $endDate.ToString('yyyy-MM-dd') | |
#$archiveDate = (Get-Date -Day 10).ToString('yyyy_MM_dd') | |
$archiveFile = "journaling " + $archiveDate + ".pst" | |
$archiveFileDir = "\\servername\d$\" | |
$archiveFilePath = $archiveFileDir + $archivefile | |
# Make a secondary copy at the end (optional) | |
# [Output Examples] | |
# archiveEnable2ndCopy = $true | |
# archiveFileDir2ndCopy = "\\FileServer\Archive_PST\Secondary_Backup\" | |
# archiveFilePath2ndCopy = "\\FileServer\Archive_PST\Secondary_Backup\archive 2016_01_31.pst" | |
$archiveEnable2ndCopy = $true | |
$archiveFileDir2ndCopy = "\\FileServer\Archive_PST\Secondary_Backup\" | |
$archiveFilePath2ndCopy = "$archiveFileDir2ndCopy" + "$archivefile" | |
# Log date & time (Set current date and time for use as archive job name and log file name) | |
$dateTime = Get-Date -format "yyyyMMdd_hhmmsstt" | |
# Define mailbox export request job name (for New-MailboxExportRequest cmdlet) | |
# Note: To ensure uniqueness in order for Get-MailboxExportRequest cmdlet to identify the correct job as Complete, | |
# the default setting of $archiveJobName below defines the archive job string using journal mailbox name, archive date and current date-time | |
# In addition, the script also checks whether the same mailbox export request job name exists and will attempt to remove the job entry beforehand if it does. | |
# [Output Examples] | |
# archiveJobName = messagejournal 2016_01_31 20160202_030034AM | |
$archiveJobName = $journalMailboxName + " " + $archiveDate + " " + $dateTime | |
# Define search date string for email message deletion after archiving (by Search-Mailbox cmdlet) | |
# Note (again): The default settings specify email messages of previous month. | |
# [Output Examples] | |
# searchStartDate = 01/01/2016 | |
# searchEndDate = 01/31/2016 | |
# searchDateRange = Received:01/01/2016..31/01/2016 | |
$searchStartDate = $startDate.ToString('MM/dd/yyyy') | |
#$searchEndDate = (Get-Date).AddDays(- (Get-Date).Day).ToString('MM/dd/yyyy') | |
#$searchEndDate = $endDate.ToString('MM/dd/yyyy') | |
$searchEndDate = (get-date).AddDays(-11).ToString('MM/dd/yyyy') | |
$searchDateRange = "Received:" + $searchStartDate + ".." + $searchEndDate | |
# ---------------------------------------- | |
# 2. DEFINING LOG VARIABLES | |
# ---------------------------------------- | |
# Log file (stdout, stderr) | |
$logFilePath = "D:\Scripts\Log\Log_Email_Archive_$($archiveDate)_$($dateTime).log" | |
# ---------------------------------------------------------------------------------------------------------------- | |
# 3. DEFINING SEARCH-MAILBOX VARIABLES FOR LOGGING MESSAGES SEARCHED AND DELETED FROM JOURNAL MAILBOX | |
# ---------------------------------------------------------------------------------------------------------------- | |
# Specify a mailbox (TargetMailbox) and a folder (TargetFolder, within the mailbox) different from the journal mailbox for | |
# logging email messages searched and deleted under a specified folder within a specified mailbox | |
# An email message with a zip attachment (CSV inside, listing all email messages returned by the search) will be generated in | |
# the specified mailbox under the specified folder. Multiple email messages may be generated as needed by Search-Mailbox cmdlet | |
# This logging features is Exchange-native and provided by Search-Mailbox cmdlet. | |
# (In contrast, the logging feature in comment section 4, further down below, is provided by this script) | |
# Definitons from TechNet on Search-Mailbox: https://technet.microsoft.com/en-us/library/dd298173(v=exchg.150).aspx | |
# TargetMailbox: "The TargetMailbox parameter specifies the identity of the destination mailbox where search results are copied." | |
# (The mailbox should be precreated by Exchange administrator) | |
# TargetFolder: "The TargetFolder parameter specifies a folder name in which search results are saved in the target mailbox." | |
# (The folder, within the mailbox, is created in the target mailbox upon execution.) | |
$saveSearchLogMailbox = "Specify a different mailbox name here for saving log file of Search-Mailbox results" | |
$saveSearchLogFolder = "Specify a different folder name Here for saving log file of Search-Mailbox results" | |
# -------------------------------------------------------------------- | |
# 4. DEFINING EMAIL VARIABLES FOR MAILING LOG AND RESULTS | |
# -------------------------------------------------------------------- | |
$emailSender = "Sender <sender@wandersick.com>" | |
$emailRecipient = "Recipient A <recipienta@wandersick.com>", "Recipient B <recipientb@wandersick.com>" | |
#$emailCc = "Recipient C <recipientc@wandersick.com>" | |
#$emailBcc = "Recipient D <recipientd@wandersick.com>" | |
$emailSubject = "Journaling Email Archive COMPLETE - " + $endDate.ToString('yyyy/MM/dd') + " - Log Attached" | |
$emailBody = "This is an automated message after email archiving scheduled task has completed. Please check attached log file as well as $saveSearchLogFolder (folder) within $saveSearchLogMailbox (mailbox) for any problems." | |
$emailSubjectFailure = "Journaling Email Archive FAILED - " + $endDate.ToString('yyyy/MM/dd') + " - Log Attached" | |
$emailBodyFailure = "This is an automated message after email archiving scheduled task has failed. Please check attached log file as well as $saveSearchLogFolder (folder) within $saveSearchLogMailbox (mailbox) for any problems." | |
$emailServer = "172.16.123.123" | |
$emailAttachment = $logFilePath | |
# ---------------------------------------- | |
# RECORDING VARILABLES TO LOG FILE | |
# ---------------------------------------- | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "[Variables]" | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$dateTime = ' $dateTime | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$endDate = ' $endDate | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$journalMailboxName = ' $journalMailboxName | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$startDate = ' $startDate | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveDate = ' $archiveDate | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveFile = ' $archiveFile | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveFileDir = ' $archiveFileDir | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveFilePath = ' $archiveFilePath | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveEnable2ndCopy = ' $archiveEnable2ndCopy | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveFileDir2ndCopy = ' $archiveFileDir2ndCopy | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveFilePath2ndCopy = ' $archiveFilePath2ndCopy | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$archiveJobName = ' $archiveJobName | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$searchStartDate = ' $searchStartDate | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$searchEndDate = ' $searchEndDate | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$searchDateRange = ' $searchDateRange | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailSender = ' $emailSender | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailRecipient = ' $emailRecipient | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailCc = ' $emailCc | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailSubject = ' $emailSubject | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailBody = ' $emailBody | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailSubjectFailure = ' $emailSubjectFailure | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailBodyFailure = ' $emailBodyFailure | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailServer = ' $emailServer | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$emailAttachment = ' $emailAttachment | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$PSScriptRoot = ' $PSScriptRoot | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output '$logFilePath = ' $logFilePath | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
# ---------------------------------------- | |
# EXECUTING MAIN PROCEDURE | |
# ---------------------------------------- | |
# Create an archiving job (an export request of journal mailbox within last month, with a job name that is uniquely identified, to specified location) | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Exporting items between $startDate and $endDate" | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
# Ensure no job of the same name exists. | |
# Get-MailboxExportRequest -Name $archiveJobName | Remove-MailboxExportRequest -confirm:$false | |
Get-MailboxExportRequest -Name $archiveJobName | Remove-MailboxExportRequest -confirm:$false | |
New-MailboxExportRequest -ContentFilter "(Received -ge '$startDate') -and (Received -lt '$endDate')" -Mailbox $journalMailboxName -FilePath $archiveFilePath -Name $archiveJobName -IncludeFolders "#Inbox#" -ExcludeDumpster:$true | tee $logFilePath -Append | |
#New-MailboxExportRequest -ContentFilter "(Received -ge '$startDate') -and (Received -lt '$endDate')" -Mailbox $journalMailboxName -FilePath $archiveFilePath -Name $archiveJobName | tee $logFilePath -Append | |
#New-MailboxExportRequest -ContentFilter "(Received -ge 'Nov 22 2017')" -Mailbox $journalMailboxName -FilePath $archiveFilePath -Name $archiveJobName | tee $logFilePath -Append | |
# Wait for the archiving job to complete | |
while (!(Get-MailboxExportRequest -Name $archiveJobName -Status Completed)) | |
{ | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Still exporting... Waiting 30 minutes for it to complete..." | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Get-MailboxExportRequest -Name $archiveJobName | Get-MailboxExportRequestStatistics | fl | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Start-Sleep -s 1800 | |
} | |
# To be safe before deletion, double-check the Complete status of email archiving | |
$emailArchivingStatus = Get-MailboxExportRequest -Name $archiveJobName -Status Completed | select -expand status | |
if ($emailArchivingStatus -eq "Completed") | |
{ | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Export completed." | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
# Getting more details for manual verification/troubleshooting in log file | |
Get-MailboxExportRequest -Name $archiveJobName | fl | tee $logFilePath -Append | |
Get-MailboxExportRequest -Name $archiveJobName | Get-MailboxExportRequestStatistics | fl | tee $logFilePath -Append | |
# Optional: Clean up (but Get-MailboxExportRequest will no longer return information of the previous job for troubleshooting; instead, check log file for troubleshooting) | |
# Get-MailboxExportRequest -Name $archiveJobName | Remove-MailboxExportRequest -confirm:$false | |
} | |
else | |
{ | |
# Report failure via email and exit script | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Export failed." | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
# Getting more details for manual verification/troubleshooting in log file | |
Get-MailboxExportRequest -Name $archiveJobName | fl | tee $logFilePath -Append | |
Get-MailboxExportRequest -Name $archiveJobName | Get-MailboxExportRequestStatistics | fl | tee $logFilePath -Append | |
# Optional: Clean up (but Get-MailboxExportRequest will no longer return information of the previous job for troubleshooting; instead, check log file for troubleshooting) | |
# Get-MailboxExportRequest -Name $archiveJobName | Remove-MailboxExportRequest -confirm:$false | |
Send-MailMessage -From $emailSender -To $emailRecipient -Cc $emailCc -Subject $emailSubjectFailure -Body $emailBodyFailure -SmtpServer $emailServer -Attachments $emailAttachment | |
Exit | |
} | |
# Check exported Archive file if is it locked | |
Do { | |
$fileinfo = [System.IO.FileInfo] (gi $archiveFilePath).fullname | |
try { | |
$stream = $fileInfo.Open([System.IO.FileMode]"Open",[System.IO.FileAccess]"ReadWrite",[System.IO.FileShare]"None") | |
$stream.Dispose() | |
$result = $false | |
Write-Output "Time: $(Get-Date). Archive is unlocked!" | |
} catch [System.IO.IOException] { | |
$result = $true | |
Write-Output "Time: $(Get-Date). Archive is still locked" | |
Out-File -FilePath $logFilePath -Append -InputObject ("Time: " + (Get-Date) + " Archive is still locked") | |
Start-Sleep -Seconds 10 | |
} | |
$result | |
} | |
Until ( $result -eq $false ) | |
# Creating a second copy to specified location | |
if ($archiveEnable2ndCopy) { Copy-Item -Path "$archiveFilePath" -Destination "$archiveFilePath2ndCopy" -Force -Confirm:$false -ErrorVariable faultCopy | tee $logFilePath -Append } | |
Out-File -FilePath $logFilePath -Append -InputObject $faultCopy | |
# In case there is any error during copying, send email and exit script so that no deletion will occur. | |
$fileHashSrc = Get-FileHash $archiveFilePath | select -expand hash | |
$fileHashDst = Get-FileHash $archiveFilePath2ndCopy | select -expand hash | |
if ($fileHashSrc -eq $fileHashDst) | |
{ | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Second file copy completed and verified successfully!!! `r`n Archive Hash $archiveFilePath : $fileHashSrc `r`n Second Archive Hash $archiveFilePath2ndCopy : $fileHashDst" | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
} | |
else | |
{ | |
# Report failure via email and exit script | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Second file copy verification failed!!! `n Archive Hash: $fileHashSrc `n Second Archive Hash: $fileHashDst" | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Send-MailMessage -From $emailSender -To $emailRecipient -Cc $emailCc -Subject $emailSubjectFailure -Body $emailBodyFailure -SmtpServer $emailServer -Attachments $emailAttachment | |
Exit | |
} | |
# Creating a log file of email messages to be deleted, then delete email (after PST export task is complete) | |
# This might have to be run multiple times (automatically) in order to get rid of all (>10000) email messages as 10000 is the limit of a single Search-Mailbox query. | |
# Except the first run, any subsequent run of the mail deletion command only happens when remaining item count is 10000. | |
do | |
{ | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Logging a list of items in journal mailbox to be deleted into $saveSearchLogFolder (Folder) of $saveSearchLogMailbox (Mailbox)" | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
# Creating a log file of email messages to be deleted | |
$remainingItemCount = Get-Mailbox -Identity $journalMailboxName | Search-Mailbox -SearchQuery $searchDateRange -LogOnly -LogLevel Full -TargetFolder $saveSearchLogFolder -TargetMailbox $saveSearchLogMailbox | select -expand ResultItemsCount | |
Write-Output '$remainingItemCount = ' $remainingItemCount | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Deleting archived messages from journal mailbox with specified date range: $searchDateRange" | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
# Delete email | |
Get-Mailbox -Identity $journalMailboxName | Search-Mailbox -SearchQuery $searchDateRange -DeleteContent -force | tee $logFilePath -Append | |
# Sleep for 5 minutes only when there are more email messages to delete (may not be required) | |
if ($remainingItemCount -eq 10000) | |
{ | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Sleep for 5 minutes" | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
start-sleep -s 300 | |
} | |
} | |
while ($remainingItemCount -eq 10000) | |
Write-Output "" | tee $logFilePath -Append | |
Write-Output "Sending an email with log to $emailRecipient cc $emailCc bcc $emailBcc " | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
# Send an email using local SMTP server with log when done. | |
# Send-MailMessage -From $emailSender -To $emailRecipient -Cc $emailCc -Bcc $emailBcc -Subject $emailSubject -Body $emailBody -SmtpServer $emailServer -Attachments $emailAttachment | |
Send-MailMessage -From $emailSender -To $emailRecipient -Subject $emailSubject -Body $emailBody -SmtpServer $emailServer -Attachments $emailAttachment |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment