Exchange 2016, 2013, 2010 mailbox backup by export to PST (PowerShell)

Exchange 2013/2010 mailbox backup by export to PST (PowerShell)

An email organization lives and dies by mailbox backups. Unfortunately, all Microsoft Exchange versions, including Exchange 2016, come with limited brick-level backup capabilities. Basically, the only available granular option is an export to PST files. This can be done via Outlook (obviously), PowerShell and in some cases also via Exchange Management Console / Control Panel. In this article I discuss the options available via PowerShell in: Exchange 2016, Exchange 2013 and Exchange 2010.

Note: To export Exchange 2007 mailboxes to PST files use the Export-Mailbox cmdlet. If you are using Exchange Online, consult this article.

Single mailbox export to PST file

Exporting mailbox contents to a PST file is achieved using the MailboxExportRequest cmdlet. It has only 2 obligatory parameters: FilePath – defines the network share path of the PST file to which you want to export the data; and Mailbox – defines the Alias, SMTP address or Display name of the mailbox you will export. Requirements:

  • The user performing the export must be a member of a role group which has the Mailbox Import Export role added. The easiest way of achieving this is running this script:
    New-ManagementRoleAssignment -Role "Mailbox Import Export" -User "<user name or alias>"

    To learn more see the “Add a role to a role group” section of this TechNet article.

  • The location to which you will export the PST file must be a shared folder.

Syntax

Here is an example of a mailbox export request, which backs up an entire mailbox to a PST file:

New-MailboxExportRequest -Mailbox <user> -FilePath \\<server FQDN>\<shared folder name>\<PST name>.pst

Limiting the scope of exported contents is possible using additional parameters, e.g.:

-ContentFilter

Specifies what conditions the contents of a mailbox have to match to be exported into the PST file. The conditions are provided in the form of standard PowerShell logical clauses with several item properties available for filtering (wildcards are supported). Example of a script that exports items received prior to 2013-01-01 with subjects beginning with fwd:

New-MailboxExportRequest -Mailbox <user> -ContentFilter {(Received -lt '01/01/2013') -and (Subject -like 'fwd*')} -FilePath \\<server FQDN>\<shared folder name>\<PST name>.pst

-ExcludeFolders and -IncludeFolders

Just what it sounds like. You can choose from all Exchange mailbox folders. There are also two interesting features available:

  • The capability to filter personal folders located under root folders using the <FolderName>/* syntax.
  • The capability to filter well known Exchange mailbox folders regardless of their name in a local language using the #<FolderName>#/* syntax.

Here is an example of a script that exports only the Inbox and Sent Items folders:

New-MailboxExportRequest -IncludeFolders "#Inbox#/*","#SentItems#" -Mailbox <user> -FilePath \\<server FQDN>\<shared folder name>\<PST name>.pst

-IsArchive

A switch parameter, which defines the archive as the only source of the export. Example:

New-MailboxExportRequest -Mailbox <user> -IsArchive -FilePath \\<server FQDN>\<shared folder name>\<PST name>.pst

-Name

Sets the name of an export request. Useful for tracking or if you want to set more than 10 export requests per a single mailbox. This is because by default Exchange assigns only 10 consecutive names to export requests related to a single mailbox (starting with MailboxExport through MailboxExport9) and then stops. To proceed when all 10 default export request names have been taken, you have to either flush your export requests or start assigning your own names using the Name parameter. Example:

New-MailboxExportRequest -Name <unique name> -Mailbox <user> -IsArchive -FilePath \\<server FQDN>\<shared folder name>\<PST name>.pst

Additional information

A single MailboxExportRequest script can, of course, contain multiple parameters, including ones I didn’t mention. For a full list of available parameters, as well as syntax information and other details, consult the link below. TechNet: single mailbox exports to PST details

Bulk mailbox export to PST file


The requirements here are identical as in the case of single mailbox exports:

  • The user performing the export must be a member of a role group which has the Mailbox Import Export role added (see previous section for more).
  • The location to which you will export the PST file must be a shared folder.

Method 1

Save all mailboxes to a variable (in my case it’s AllMailboxes):

$AllMailboxes = Get-Mailbox

Export all mailboxes to PST files with names based on mailbox aliases (to use a different mailbox property replace the phrase “Alias” with its name):

$AllMailboxes|%{$_|New-MailboxExportRequest -FilePath \\<server FQDN>\<shared folder name>\$($_.Alias).pst}

Additional parameters can be used just as in single mailbox exports (see the first section of this article).

Method 2

Run the below script for the same effect as in Method 1 (the only difference is the use of the foreach command instead of piping):

foreach ($Mailbox in (Get-Mailbox)) { New-MailboxExportRequest -Mailbox $Mailbox -FilePath "\\<server FQDN>\<shared folder name>\$($Mailbox.Alias).pst" }

Limiting the scope of exported mailboxes

You will notice that the methods I describe result in exporting all mailboxes located on your servers. If you want to limit the scope of exported mailboxes, you can do so e.g. using the Get-Mailbox -Filter parameter. Here is an example of a script which lists mailboxes belonging to a security group called export1.

Get-Mailbox -Filter {MemberOfGroup -ne $export1}

NOTE: Using the -Filter parameter with the Get-Mailbox cmdlet results in excluding mailboxes that are defined in the parameter. This is why, to limit the scope of exported mailboxes to e.g. Batch1, you have to use the -Filter parameter to exclude all mailboxes that are not part of Batch1 – hence the use of the -ne (not equals) operator. Adding the -Filter parameter to the Get-Mailbox cmdlets in Method 1 and Method 2 scripts will result in limiting the scope of exported mailboxes. View the full list of filterable Get-Mailbox properties Get-Mailbox cmdlet explained

Mailbox backups to PST file: The bright and the dark side

All in all the drawbacks seem to outweigh the advantages, mainly due to clunky PST handling options and due to the files themselves being rather unstable:

Pros Cons
  • Brick-level backups with item filtering capability
  • Support for mass mailbox backups
  • Customizability
  • Available for free
  • Fragility and corruptibility of PST files
  • Limited search capability (only per-PST, upon import)
  • No item preview
  • No central management for backup jobs, storages, etc.
  • Lack of backup statistics
  • Increased execution difficulty due to PowerShell usage
  • Risk of data loss
  • Backup content preview only via Outlook
  • No versioning or incremental backup options (high disk space consumption)
  • Scheduling possible only via Windows Task Manager

Easy brick-level Exchange mailbox backups

You can have all the advantages of a PowerShell assisted mailbox-to-PST backup without its drawbacks. CodeTwo Backup for Exchange allows for secure granular mailbox backups to a stable and easily managed database. The software allows for scheduling multiple simultaneous backup and restore jobs, includes a smart versioning mechanism, full item search and preview, and additionally, allows for archiving storages to PST files as one of 2 available archiving models (learn more…).

Exchange 2016, 2013, 2010 mailbox backup by export to PST (PowerShell) by

38 thoughts on “Exchange 2016, 2013, 2010 mailbox backup by export to PST (PowerShell)


    • Hi reredok,

      I’m not sure if I understand the question, but keep in mind that there is no default limit of simultaneous export requests (as far as I know). Exchange can automatically generate 10 MailboxExportRequest names, but you should still be able to add new ones with custom names.

      Also, you can remove exports request using the Remove-MailboxExportRequest cmdlet: https://technet.microsoft.com/en-us/library/ff607464(v=exchg.160).aspx

      Please let me know if this helps,
      Adam

      • thanks, I mean:
        ### start export
        New-MailboxExportRequest -ContentFilter …..

        ### determine if Export is ready
        while(!(Get-MailboxExportRequest … -Status Completed)) …..
        {
        # next PS
        }

        while… doesn’t work for me to wait until export is ready.
        hope now it’s clearer.

        thx+

        • Hi reredok,

          Here’s a simple script that meets your requirement:

          $nRequest = 0;

          foreach ($mailbox in (Get-Mailbox))
          {
          New-MailboxExportRequest -ContentFilter ...;
          while ((Get-MailboxExportRequest -Name $nRequest).Status -ne "Completed" ...)
          {
          Start-Sleep -s 2
          }
          $nRequest++;
          }

          Note! If you only use the -ne “Completed” condition, the script is at risk of falling into an endless loop when an export request fails, is suspended, etc (see Parameters > Status: https://technet.microsoft.com/en-us/library/ff607479(v=exchg.160).aspx). You should either prepare a condition that takes this into account or add a timeout, e.g.:

          ...
          while($nTimeout -le 30 -And (Get-MailboxExportRequest -Name $nRequest).Status -ne "Completed")
          {
          Start-Sleep -s 2
          $nTimeout += 2
          continue;
          }
          ...

          Hope this helps,
          Adam

  1. None of the commands are working.

    [PS] C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Exchange Server 2010>New-ManagementRoleAssignment -R
    ole “Mailbox Import Export” -User “someuser”
    The term ‘New-ManagementRoleAssignment’ is not recognized as the name of a cmdlet, function, script file, or operable p
    rogram. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:29
    + New-ManagementRoleAssignment <<<MailboxExportRequest
    The term ‘MailboxExportRequest’ is not recognized as the name of a cmdlet, function, script file, or operable program.
    Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:21
    + MailboxExportRequest <<<Get-ManagementRoleAssignment -r
    oleassignee someuser | select-object role
    The term ‘Get-ManagementRoleAssignment’ is not recognized as the name of a cmdlet, function, script file, or operable p
    rogram. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:29
    + Get-ManagementRoleAssignment <<<New-ManagementRoleAssignment -R
    ole “Mailbox Import Export” -User “someuser”
    The term ‘New-ManagementRoleAssignment’ is not recognized as the name of a cmdlet, function, script file, or operable p
    rogram. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:29
    + New-ManagementRoleAssignment <<<

  2. Hi there,

    I’ve got a problem with cmdlet “New-MailboxExportRequest”, too. I’m running my powershell as an admin, I assigned my Malibox Import Export, but Mailbox Export Request doesn’t work. It’s displaying this error:

    “New-MailboxExportRequest : The term ‘New-MailboxExportRequest’ is not recognized as the name of a cmdlet, function, scr
    ipt file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is corre
    ct and try again.”

    I was finding potential solutions of this problem, but I didn’t find. So, could I ask you for help? I’d be very grateful, if you help me.
    Thank you for any reply.

    Daniel.

    • Hi Daniel,

      Please verify that the Mailbox Export Role has been correctly assigned by running:

      Get-ManagementRoleAssignment -roleassignee (name_of_user) | select-object role

      Also – which version of Exchange are you running?

      -Adam

    • Hi David,

      To run a script using the Task Scheduler, follow the steps below:

      1. Save the script you want to run to the .ps1 format.
      2. Open the Task Scheduler, go to Task Scheduler Library and create a new task (right-click on the Task Scheduler Library).
      3. In the new task window, go to the Actions tab, click the New… button and, in the resulting window, provide:

      – Action: Start a program
      – Program/script: powershell.exe (or browse the file: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe)
      – Add arguments: -nologo -command “path to the file with the powershell script”

      4. Other tabs in the task window i.e. General, Triggers, Conditions and Settings set up the way you need.
      5. Click OK to save the task.

      Hope this helps!

      Adam

  3. Thanks for sharing this Information Adam. You have explained it really well. But whenever I try for backup Exchange Mailbox to PST using commands, I get error “You don’t have permission to export”.
    Manual way is really challenging task for me therefore I have purchased a tool for backup by exchange database in PST. Its name is SysTools Exchange Recovery Software and it works very well.

    • Hi Ben,

      It might be that the account you are using does not have the Mailbox Import Export role assigned. You can correct this by running the below command:

      New-ManagementRoleAssignment -Role "Mailbox Import Export" -User "user name or alias"

      Hope this helps,
      Adam

  4. I would like to use the “for each” method with a filter to select which mailboxes will be exported. This filter works:
    get-mailbox -filter {CustomAttribute1 -eq "Name"}
    However, when I try to add the “for each) option like this:
    foreach ($Mailbox in (get-mailbox -filter {CustomAttribute1 -eq "Norwood"}
    I get an error in the script editor telling me about missing ). Can you explain what I’ve done wrong?

    • Hi Kelley,

      To export mailboxes using “foreach” command, you would have to use a script like the one below:

      foreach ($AllMailboxes in (Get-Mailbox -Filter {CustomAttribute1 -eq "Name"}))
      {
      $Today=(get-date).tostring("yyyy-MM-dd_hh-mm-ss");
      $PastDate=(get-date).AddMinutes(-X);
      $FileName=$AllMailboxes.Alias+"_"+$Today+".pst";
      New-MailboxExportRequest -Mailbox $AllMailboxes -ContentFilter {(Received -gt $PastDate)} -FilePath "Network share FQDN\$FileName"
      }

      Where the X parameter needs to be replaced with the value of your choice.

      Additionally, if you have Exchange 2010, make sure you are assigned the Mailbox Import Export role. You can add that role using the following command:

      New-ManagementRoleAssignment –Role “Mailbox Import Export” –User “Username”

      Hope this helps!
      Adam

  5. Hello Adam,

    Can we restore a specific user mail box from a recovery database to a pst file?
    I run below mentioned command but, i get error
    [PS] C:\Mgrshr\PowerShell>New-MailboxExportRequest -Database recoveryDB -Mailbox “user” -FilePath path\mailbox.pst
    A positional parameter cannot be found that accepts argument ‘-Database’.
    + CategoryInfo : InvalidArgument: (:) [New-MailboxExportRequest], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,New-MailboxExportRequest

    IT is the same when i use -SourceDatabase instead of -Database.

  6. I know New-MailboxExportRequest isn’t available for Exchange Online, but if you have a hybrid deployment, is it possible to run a script on the on-premises Exchange server and export mailboxes that reside in the cloud? Or would you need to move the mailbox to the on-premises database first?

  7. Hello Guys,

    maybe you want to Export pst´s using SamAccountName from a Security Group…

    foreach ($AllMailboxes in (Get-ADGroupMember “Security Group” | Select-Object SamAccountName)) { New-MailboxExportRequest -Mailbox $AllMailboxes.SamAccountName -FilePath “network share FQDN\$($AllMailboxes.SamAccountName).pst” }

    Cheers

    • Hi Sebastian,

      Thanks for the input!

      (Hope you don’t mind – I put the ‘network share FQDN’ part of your script back in. WordPress tends to skip text when you e.g. put it inside angle brackets)

      Best regards,
      Adam

  8. Hi,
    I have two question to this article: 1. usually I create the archive in Outlook via Import/Export function and filter received on or before 31/12/2014 for example (all sent items have also the flag received). I run it and really rarely it appears to have less items in the PST as when I run a advanced search on the users mailbox and let count the items. So this would mean there was something incorrect with the export process. But how can I do this when I use the script? How to compare the amount of items.
    2. I have created a PST via Outlook and via script. in the script-PST there are about 1800 more items than in the Outlook-PST with the same filter setup. What is the difference between the two processes?

    Best regards
    Torsten Kraft

  9. There is option for versioning and incremental backup: use contentfilter. Though the date syntax is pain and depends your cultural formatting. Do not remember to use date variables in filenames!
    New-MailboxExportRequest -ContentFilter {(Received -lt ’03/13/2010′) -and (Received -gt ’03/13/2010′)} -Mailbox “SharedMailbox” -Name Requestname -FilePath \\ExServer1\Imports\Name.pst

    • Hi Bluebull,

      Actually, to achieve the level of versioning that I was thinking of, you would have to schedule a script like the one below (rough draft – sorry about the quality) to run every X, where X is as short a period of time as possible:

      foreach ($AllMailboxes in (Get-Mailbox)) { $Today=(get-date).tostring("yyyy-MM-dd_hh-mm-ss"); $PastDate=(get-date).AddMinutes(-X); $FileName=$AllMailboxes.Alias+"_"+$Today+".pst"; New-MailboxExportRequest -Mailbox $AllMailboxes -ContentFilter {(Received -gt $PastDate)} -FilePath "Network share FQDN\$FileName" }

      In my example the PSTs would contain data from X-minute time intervals, but since the aim is to save a version of an item after every change, you may even need X-second intervals. The drawbacks of this solution are huge disk space consumption, almost impossible forensics, and so on.

      Best regards,
      Adam

  10. I did this before on Exchange 2007 or 2010, can’t remember. Does Exchange 2013 still require the computer running the powershell commands to be 32-bit? That was the issue I had last time. I had to create a new Win7 VM, connect to the clients VPN, then was able to install the Exchange Admin Tools and run the commands against an OU. Seemed to work well.

    • @Patil
      (Sorry for the delay answering.) Not automatically. You would have to create and share the folders first and then use the below script to export the PSTs.

      foreach ($AllMailboxes in (Get-Mailbox)) { New-MailboxExportRequest -Mailbox $AllMailboxes -FilePath “\\[server FQDN]\[folder layer]\$($AllMailboxes.Alias)\[PST filename].pst” }

      @Blake
      No, the 32-bit limitation has been gone since Exchange 2010. On Exchange 2007 you needed a 32-bit machine to install Exchange Management Tools, which were necessary to use the Export-Mailbox and Import-Mailbox cmdlets.

      Hope this helps,
      Adam

  11. Can I modify script to export psts to their corresponding folder names.
    foreach ($AllMailboxes in (Get-Mailbox)) { New-MailboxExportRequest -Mailbox $AllMailboxes -FilePath “\\\\$($AllMailboxes.Alias).pst” }

    • Hello abdikarim!

      Try our free tool, CodeTwo Outlook AutoConfig. With this program setting up your Outlook is as easy as entering your email address. The tool does the rest, properly configuring all mail server details in Outlook.

Leave a Reply

Your email address will not be published.

*

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>