Exchange 2013/16 Journal Mailbox Archive-to-PST PowerShell Script Automation with Reporting
Recent Exchange versions have built-in support of journaling for recording all inbound and outbound email messages for backup or compliance reasons. Overtime, the journal mailbox grows so large and needs to be trimmed or pruned. This script was written to automate the process.
This article documents a PowerShell maintenance script I have written for reporting and automating a monthly archive-to-PST process of the Exchange 2013 journaling mailbox. (Based on reader feedback, it also suits Exchange 2016 Standard.)
A log file is created under a specified directory during each execution. An email is sent to specified email addresses with the log file when done. The email message subject indicates COMPLETE/FAILURE.
In addition, a list of email messages returned from search and deleted by Search-Mailbox cmdlet will be available as zip(csv) attachments in another specified mailbox and folder as mentioned in the message body of above email.

This article documents a PowerShell maintenance script I have written for reporting and automating a monthly archive-to-PST process of the Exchange 2013 journaling mailbox. (Based on reader feedback, it also suits Exchange 2016 Standard.)
Archiving Concept
This script uses the PowerShell cmdlet New-MailboxExportRequest -Mailbox to export Exchange Journaling Mailbox of previous month (e.g. 2016-01-01 to 2016-01-31) as a standard PST file (e.g. archive 2016_01_31.pst) to specified locations (up to two locations) and then uses Search-Mailbox -DeleteContent to delete email messages within the date range if successful. It is designed to be run at the beginning of each month (e.g. 2/Feb/16) using Windows Task Scheduler.Email Alerting, Reporting and Logging

A log file is created under a specified directory during each execution. An email is sent to specified email addresses with the log file when done. The email message subject indicates COMPLETE/FAILURE.
In addition, a list of email messages returned from search and deleted by Search-Mailbox cmdlet will be available as zip(csv) attachments in another specified mailbox and folder as mentioned in the message body of above email.
Safety Measure to Prevent Accidental Email Deletion
In case mail archiving has failed, script will send an alert mail and exit so that no mail deletion will occur. In technical terms, when status of Get-MailboxExportRequest is not "Completed", script keeps on waiting (looping) until it is complete. If the loop is broken or script receives any status other than "Completed", execution will be terminated and failure will be reported by email.Assumptions and Requirements
- PowerShell 3.0 or above
- Execute this script on Exchange server where (preferably):
- System Locale is English (United States)
- Short date format (for en-US) is MM/dd/yyyy
- Sufficient disk space for storing PST files in the specified location(s)
Getting Started – Script Usage and Instructions
- Edit variable parameters as required (See sections 1-4 in the script below.)
- Save the script in a local folder e.g. C:\scripts\ws_email_archiving_script.ps1
- To export email of last month, the script should be scheduled to run any day within the current month.
For example, to export Jan 2016 email, running the script any day within Feb 2016 would do; the beginning of month is recommended (e.g. 2/Feb/16)
Setting up Windows Task Scheduler
Program/script:- C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
- -PSConsoleFile "C:\Program Files\Microsoft\Exchange Server\V15\Bin\exshell.psc1" -command ". 'C:\Program Files\Microsoft\Exchange Server\V15\Bin\Exchange.ps1'; &'C:\scripts\ws_email_archiving_script.ps1'"
- C:\Scripts
- "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PSConsoleFile "C:\Program Files\Microsoft\Exchange Server\V15\Bin\exshell.psc1" -command ". 'C:\Program Files\Microsoft\Exchange Server\V15\Bin\Exchange.ps1'; &'C:\scripts\ws_email_archiving_script.ps1'"
PowerShell Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# WS Email Archiving - Journal Mailbox Archiving PowerShell Script for Exchange 2013 | |
# Written by wandersick (https://tech.wandersick.com/2016/07/powershell-automation-of-journal.html) | |
# Version: 1.3 (20200614) | |
# 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) | |
# (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') | |
$archiveFile = "archive " + $archiveDate + ".pst" | |
$archiveFileDir = "\\localhost\e$\Archive_PST\" | |
$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 = $false | |
$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') | |
$searchDateRange = "Received:" + $searchStartDate + ".." + $searchEndDate | |
# ---------------------------------------- | |
# 2. DEFINING LOG VARIABLES | |
# ---------------------------------------- | |
# Log file (stdout, stderr) | |
$logFilePath = "C:\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" | |
# Tip: The above variables refer to TargetMailbox and TargetFolder from Search-Mailbox cmdlet respectively. | |
# Read the above Microsoft URL (definition of Search-Mailbox) for how to configure these two parameters. | |
# | |
# If still unsure, for these two variables, you may specify '$saveSearchLogMailbox = administrator' and | |
# '$saveSearchLogFolder = SearchAndDeleteLog' where logs will be emailed to a to-be-created/existing folder | |
# named 'SearchAndDeleteLog' within the mailbox of 'administrator'. | |
# -------------------------------------------------------------------- | |
# 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 = "Monthly Email Archive COMPLETE - " + $startDate.ToString('yyyy/MM') + " - 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 = "Monthly Email Archive FAILED - " + $startDate.ToString('yyyy/MM') + " - 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 | |
New-MailboxExportRequest -ContentFilter "(Received -ge '$startDate') -and (Received -lt '$endDate')" -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 -Bcc $emailBcc -Subject $emailSubjectFailure -Body $emailBodyFailure -SmtpServer $emailServer -Attachments $emailAttachment | |
Exit | |
} | |
# Creating a second copy to specified location | |
if ($archiveEnable2ndCopy) { Copy-Item -Path $archiveFilePath -Destination $archiveFilePath2ndCopy -Force -Confirm:$false | tee $logFilePath -Append } | |
# 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." | 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." | tee $logFilePath -Append | |
Write-Output "" | tee $logFilePath -Append | |
Send-MailMessage -From $emailSender -To $emailRecipient -Cc $emailCc -Bcc $emailBcc -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 |
Download
⭐ The script can be downloaded at GitHub
Word of Mouth
Below are some of the kind comments left by users of this script. (Thanks!)
- "We have some very large journaling mailboxes that we've been racking our brains trying to figure out what to do with to stop the sprawl. We're on Exchange 2016 Standard, so we're limited on our database count. This script has made it really easy for us to dig out emails by month and save them off to PST that we can store out on second tier storage for archive. Thanks for this!"
- "I've used your script for a couple of years. It's GREAT and do a GREAT job. Thank you very much!"
Release History
Ver | Date | Update |
1.3 | 20200614 | - Add missing bcc parameters in the first two lines of Send-MailMessage - Change default setting of archiveEnable2ndCopy to false as it should not be commonly enabled - Add a tip in the comment section of the script at part 3 to make it easier to configure the parameters |
1.2 | 20171022 | - Turn journal mailbox name into a variable - Further ensure New/Get-MailboxExportRequest job name uniqueness by naming it with current date time (in yyyyMMdd_hhmmsstt) - Remove unused variables, scriptDir, startDateShort and endDateShort - Improve script comments |
1.1 | 20160712 | First public release |
1.0 | 20160314 | First internal release |
Welcome to support this project by buying a cup of coffee if this tool is useful to you. 😊 Thanks! If you would love the script to be further developed, you may engage professional services on one of the freelancing platforms.
References
- How can I move Exchange items to a PST using PowerShell?
http://serverfault.com/questions/511610/how-can-i-move-exchange-items-to-a-pst-using-powershell
- MailboxExportRequest ContentFilter is “Received -ne $null” when querying by date
http://serverfault.com/questions/591798/mailboxexportrequest-contentfilter-is-received-ne-null-when-querying-by-date
- Cannot get Exchange PowerShell script to run under Scheduled Tasks
http://serverfault.com/questions/576302/cannot-get-exchange-powershell-script-to-run-under-scheduled-tasks
Great Idea! thanks for that, How i can change this for take daily backups?
ReplyDeleteHi Enes S, thanks for your interest in the script. To clarify your question, do you mean that you want to apply the script for email messages of the previous day? (Note: this script was designed and extensively tested for email messages of the previous month only)
DeleteTo answer your question, you need to (at least):
1. Configure $endDate and $startDate (required for New-MailboxExportRequest cmdlet to export to PST)
2. Configure $searchStartDate and $searchEndDate (required for Search-Mailbox cmdlet to delete exported email messages)
3. Update the content of the email message to be sent after the process.
I have updated (reorganized) the script and the blog post a bit in the hopes that it will be more readable and 'tweakable' in order to use for other purposes.
I have tried not to miss any key things. Please bare with me if I do. :)
We have some very large journaling mailboxes that we've been racking our brains trying to figure out what to do with to stop the sprawl. We're on Exchange 2016 Standard, so we're limited on our database count. This script has made it really easy for us to dig out emails by month and save them off to PST that we can store out on second tier storage for archive. Thanks for this!
ReplyDeleteThanks for sharing your experience with the script on Exchange 2016 Standard!
DeleteSince there are newer Exchange Server major releases now, I will consider better naming the title of this post so that people using those versions may still benefit from it. (If you or anyone have done any readaptation to fit specific use cases, that would be nice to know as well.)
Great Idea! thanks for that, How i can change this for take daily backups
ReplyDeleteHi Basem,
DeleteThanks for your question. Below are the variables you need to adjust (primarily):
1. New-MailboxExportRequest cmdlet (handles exporting email to PST files)
- $endDate
- $startDate
2. Search-Mailbox cmdlet (handles deletion of exported email)
- $searchStartDate
- $searchEndDate
In case you need to further develop this script, consider hiring an expert through freelancing marketplaces. By coincidence, I just wrote an article on the topic.
Hello wandersick,
ReplyDeleteI use your script from couple of years. Its GREAT and do GREAT job. Thank you very much!!!
I`m not good in scripting but because I have some issues with it I make modifications.
It runs every 10 days as it keep at least 10 days history in Journal mailbox and in my case it make 10GB .pst achives.
And because New-MailboxExportRequest -ContentFilter cant work with dates with localization other from "en-US" I added it temporally for session /Exchange 2013, Server 2012R2/
And after exporting the .pst file is stay locked sometimes for a few more minutes, so I added a check before start coping to secondary location.
I don't know if it's convenient to share the changes here, if you find them useful. Excuse me if it's not appropriate.
Thanks again!
...
I cant post ... too big... share in google drive:
https://drive.google.com/file/d/1OqVNfsTFRIWrrl0MBIu93CWOQZbzcvG4/view?usp=sharing
Hello connann2,
DeleteI am glad to see you successfully implement the script in a Windows Server with a locale other than en-US and contribute your solution for that (along with improvements like checking whether exported archive file is locked and enabling ExcludeDumpster)
Thanks for sharing your experience! In the future, I may integrate your changes into the main script so that others can be benefited. (I will credit you for that of course. Kindly let me know in case that is not OK, and feel free to let me know how you want to be credited, e.g. an URL and a name if not 'connann2'.)
P.S. I would suggest using a service like GitHub Gist for posting code, or even better, fork the GitHub repository and then share yours. :)
Have a good day!
Hello, wandersick,
DeleteThank you for the reply. Don't worry about credit my name, I'll be happy if you find something useful from my modifications. I still use your work for free :)
I forgot to mention that I saw a problem with the Search-Mailbox and New-MailboxExportRequest functions - one uses GMT time and the other local time. And so there is a difference of several hours between the limit for archived and deleted emails. So I replaced endDate = (Get-Date "00:00:00") with
$ endDate = (Get-Date [TimeZoneInfo] :: Local) .BaseUtcOffset.ToString () ...
This may be a local problem, I'm GMT + 2 hours.
Thank you again!
That's good to know.
DeleteThanks for the improvement you have brought to the script again!
Hello, wandersick.
DeleteBig thank's for your script!
Default script is worked. But if I changed to run this script with another dates script end with error "Second file copy verification failed."
I didn't change default $archiveEnable2ndCopy = $false
Do you help me?
Could you please try configuring a secondary copy by setting $archiveEnable2ndCopy = $true and configure a UNC path to store the secondary copy by setting $archiveFileDir2ndCopy (refer to the example in the script)? Would it work after doing so?
Delete