Reporting delegate access to Exchange mailboxes

All current versions of Exchange 2013 (up to and including CU6) and Exchange Online (Office 365) contain a bug that can compromise the ability of companies to comply with discovery orders. The bug means that a user can remove items from a mailbox without copies being retained, even if the mailbox is under the control of a litigation or in-place hold. The good news is that the problem only appears with the Outlook Web App (OWA) client. It is not possible to exploit the retention hole in Outlook or any mobile client, including OWA for Devices.

Obviously, anything that affects compliance is a serious issue. No one wants to be in front of a judge and admit that their email system is incapable of retaining all of the items specified in a discovery action, which is exactly the purpose of the immutability features incorporated into Exchange 2010 and enhanced in Exchange 2013. Microsoft is working on a fix and this should appear in first in Exchange Online and then in Exchange 2013 CU7. No date is yet available for when this will happen.

In the interim, Microsoft suggested two workarounds in KB2996477. These are:

  • Put a hold on all users who are participating in delegated scenarios.
  • Disable OWA for users who have delegated access to their mailbox.

The first suggestion addresses the fact that the hole only appears when some form of delegation (non-owner access) is in place for the mailbox as this access is used to move or delete items from a mailbox without preservation of the copies of the deleted items within the Recoverable Items structure of the mailbox. It is this preservation that allows the apparently deleted items to be indexed by Exchange and therefore discoverable and accessible through administrator-initiated eDiscovery searches.

Placing a hold on everyone who is involved in some form of mailbox delegation (such as accessing a shared mailbox or the classic “manager-administrative assistant” scenario) ensures that items moved or deleted via the delegation are preserved and is therefore a solution. However, some practical difficulties face administrators who want to take this action.

The first challenge is to discover what users are accessing shared mailboxes. It’s possible that you already have a list of shared mailboxes and know who is using these mailboxes, but if not, you can run this code to create a quick list:

Get-Mailbox –RecipientTypeDetails ‘SharedMailbox’ | Get-MailboxPermission | where {$_.user.tostring() -ne "NT AUTHORITY\SELF" -and $_.IsInherited -eq $false} | Format-Table Identity, User, AccessRights –AutoSize

Identity                                       User                        AccessRights
--------                                       ----                        ------------ users/EMEA Help Desk (IT) CONTOSO\TRedmond            {FullAccess} users/EMEA Help Desk (IT) CONTOSO\Ito                 {FullAccess} users/APJ Help Desk       CONTOSO\TRedmond            {FullAccess} users/APJ Help Desk       CONTOSO\Ako                 {FullAccess} users/APJ Help Desk       CONTOSO\JChen               {FullAccess} users/Contoso PR queries  CONTOSO\TRedmond            {FullAccess} Queries        CONTOSO\TRedmond            {FullAccess} Queries        CONTOSO\Akers               {FullAccess}

However, shared mailbox delegation is the least likely route to exploit the bug. My judgment is that it is more likely that a user who seeks to mask his actions will use folder-level delegation. OWApermissionsUnderstanding who has access to individual folders in other mailboxes is a more difficult task, if only because administrators don’t usually know when users delegate access to folders in their mailboxes to other people. This is easily done with Outlook or OWA by editing the properties of a folder and assigning other users permissions such as “Publishing Editor” or “Editor”, both of which will allow delegates to remove items from the folder.

I did a brief search of the Internet to see if I could find anything that would report delegate access to mailboxes. Quite a number of scripts focus on calendar delegates, such as, but we’re really concerned with folders that hold mail items rather than calendar appointments and meetings.

Charting out what needs to be done is easy enough. Establish a collection of mailboxes, discover what folders exist in those mailboxes, and then check the access rights on the folders to find out whether delegates exist. You might come up with code like this:

Get-Mailbox  -RecipientTypeDetails ‘UserMailbox’ | Get-MailboxFolder –Recurse -MailFolderOnly | Get-MailboxFolderPermission | Where-Object {$_.AccessRights –notlike “Owner” –or $_.AccessRights –notlike “None”} | Format-Table Identity, FolderName, User, AccessRights –AutoSize

As evident by the pile of errors that you’ll see when you run the code against either Exchange 2013 or Exchange Online, a couple of problems exist with this approach. First, you don’t have the necessary access to list the contents of other user’s mailboxes. As TechNet reminds out about the Get-MailboxFolder cmdlet, it can only “retrieve folders for a specified mailbox when the mailbox owner runs the command.”

So, while you’ll see information like this for your own mailbox:

Identity                       FolderName User            AccessRights
--------                       ---------- ----            ------------
TRedmond:\Deleted Items\ProjX  ProjX      Deirdre Redmond {PublishingEditor}
TRedmond:\Travel               Travel     Deirdre Redmond {Reviewer}

Get-MailboxFolder is a dead end for our purpose, even if your account has been granted Full Access to those mailboxes or you run the script from the Administrator account. We have to look for a different way that allows an administrator to retrieve information about the folders in user mailboxes. Fortunately, Get-MailboxStatistics comes to the rescue because it reports folder names amongst other interesting statistical information about folder contents.

Playing around with Get-MailboxStatistics gives us a script that outputs details of any non-user permission applied to a mailbox folder. This should be sufficient to identify users who have delegate access to other mailboxes who can potentially exploit the bug. I have tested this code with both Exchange 2013 CU6 and Exchange Online.

$AllUsers = Get-Mailbox -RecipientTypeDetails 'UserMailbox' -ResultSize Unlimited

ForEach ($Alias in $AllUsers)
$Mailbox = "" + $Alias.Name
Write-Host "Getting folders for mailbox: " $Mailbox
$Folders = Get-MailboxFolderStatistics $Mailbox | % {$_.folderpath} | %                     {$_.replace(“/”,”\”)}

ForEach ($F in $Folders)
$FolderKey = $Mailbox + ":" + $F
$Permissions = Get-MailboxFolderPermission -identity $FolderKey -ErrorAction                 SilentlyContinue
$Permissions | Where-Object {$_.User -notlike "Default" -and $_.User -notlike               "Anonymous" -and $_.AccessRights -notlike "None" -and $_.AccessRights -notlike            "Owner" }| Format-Table $Mailbox, User, FolderName, AccessRights -AutoSize

The normal warning about downloading and running code from a web site applies here. Do not run this code on a production server without testing it first. You have been warned…  And do please take every opportunity to improve and enhance the code. For example, a more production-ready version would output details of the permissions to a CSV-format or other file to collect data that is more easily reviewed and subsequently processed.

Speed is the second problem with our PowerShell script. Like many other examples of scripts that you can find around the Internet, this code executes reasonably quickly for a small to medium organization but will run into horrible problems if you attempt to examine mailbox permissions across an organization that spans anything more than a few hundred mailboxes. So access and speed issues are areas of concern that have to be addressed.

Running this kind of intensive PowerShell processing in the background helps somewhat when you have large amounts of data to process. MVP Serkan Varoglu explains how to do this in two posts. Part 1 explains the basics and part 2 provides some more Exchange-specific information.

But a better and more functional solution might be found with Exchange Web Services (EWS), which is the preferred programming API to develop solutions against the contents of Exchange mailboxes. Some scripts that might provide a start are available, such as the one written for Office 365 and posted in the TechNet Gallery.

However, if you’re getting serious about working with EWS my advice is to head over to the blog written by Exchange MVP Glen Scales to pick up some of the great code examples that he has posted (and explained) there. For example, this post explains how to use EWS and PowerShell to process delegate information.

Still, we have a way to identify mailboxes that participate in delegate scenarios and are therefore candidates to be put on hold. As you can imagine from this explanation, there’s quite an amount of administrative effort required to make sure that holds are applied in a systematic and ongoing way.

So what about the second workaround suggested by Microsoft, to disable OWA access for users who are on hold. First, we have to identify those mailboxes. This is readily done with a one-line EMS command:

Get-Mailbox –ResultSize Unlimited | Where-Object {$_.LitigationHoldEnabled –eq $True –or $_.InPlaceHolds –ne $Null} | Format-Table Name, LitigationHoldEnabled, InPlaceHolds

We can disable OWA access for these mailbox with an amended command:

Get-Mailbox –ResultSize Unlimited | Where-Object {$_.LitigationHoldEnabled –eq $True –or $_.InPlaceHolds –ne $Null} | Set-CASMailbox –OWAEnabled $False


Any attempt by the user to access OWA thereafter will result in them being informed that their account is disabled. In reality their account is fine and it’s just OWA access that has been turned off. They will still be able to use Outlook, ActiveSync, and OWA for Devices (and POP3 or IMAP4 if they really want).

The conclusion of this exercise is that the easiest workaround is to disable OWA access for mailboxes that are under litigation or in-place hold. It was fun to work out how to discover which mailboxes use delegate access, but the ongoing maintenance and checking that is required to keep tabs on delegate access is probably too onerous to undertake in a production environment. After all, you always have other things to do to keep Exchange on-premises or Exchange Online working well.

Follow Tony @12Knocksinna

About Tony Redmond ("Thoughts of an Idle Mind")

Exchange MVP, author, and rugby referee
This entry was posted in Cloud, Email, Exchange, Exchange 2013, Office 365, Outlook, Uncategorized and tagged , , , , , , , , , , , , , . Bookmark the permalink.

10 Responses to Reporting delegate access to Exchange mailboxes

  1. Pingback: Exchange 2013 CU6, 2010 SP3 RU7, & 2007 SP3 RU14 released & Known Issues | Jason (Izzy) Sherry's Blog

  2. Pingback: Weekly IT Newsletter – September 1-5, 2014 | Just a Lync Guy

  3. Pingback: NeWay Technologies – Weekly Newsletter #111 – September 4, 2014 | NeWay

  4. Chris says:

    CSV output:

    $AllUsers = Import-Csv users.csv | foreach {Get-Mailbox -Identity $_.emailAddress}

    Function fetch {

    ForEach ($Alias in $AllUsers)
    $Mailbox = “” + $Alias.Name
    Write-Host “Getting folders for mailbox: ” $Mailbox
    $Folders = Get-MailboxFolderStatistics $Mailbox | % {$_.folderpath} | % {$_.replace(“/”,”\”)}

    ForEach ($F in $Folders)
    $FolderKey = $Mailbox + “:” + $F
    $Permissions = Get-MailboxFolderPermission -identity $FolderKey -ErrorAction SilentlyContinue

    $Permissions | Where-Object {$_.User -notlike “Default” -and $_.User -notlike “Anonymous” -and $_.AccessRights -notlike “None” -and $_.AccessRights -notlike “Owner” } | Select-Object @{Name=’Mailbox’;Expression={[string]::join(“;”,($Mailbox))}}, User, Foldername, @{Name=’Access Rights’;Expression={[string]::join(“;”,($_.AccessRights))}}


    fetch | Export-Csv folderpermissions.csv -NoTypeInformation

  5. Mike says:

    Here’s another way to get this data into CSV format:

    $allfolders = @()

    $AllUsers = Get-Mailbox -RecipientTypeDetails ‘UserMailbox’ -ResultSize Unlimited

    ForEach ($Alias in $AllUsers)
    $Mailbox = “” + $Alias.Name
    Write-Output $Mailbox
    $mb = @{Expression={$Alias.Name};Label=”Mailbox”}
    $Folders = Get-MailboxFolderStatistics $Mailbox | % {$_.folderpath} | % {$_.replace(“/”,”\”)}

    ForEach ($F in $Folders)
    $FolderKey = $Mailbox + “:” + $F
    $Permissions = Get-MailboxFolderPermission -identity $FolderKey -ErrorAction SilentlyContinue
    $add = $Permissions | Where-Object {$_.User -notlike “Default” -and $_.User -notlike “Anonymous” -and $_.AccessRights -notlike “None” -and $_.AccessRights -notlike “Owner” }| Select $mb, User, FolderName, @{Expression={$_.AccessRights};Label=”AccessRights”}
    $allfolders += $add

    $allfolders | Export-Csv C:\tmp\GetAllFolderPermissions.csv -NoType

  6. philready says:

    How would I modify this to report to run on just one mailbox and ask for alias of this mailbox?

  7. Dan says:

    how can I modify this script , to display only the shared mailboxes with no user assigned ? Full permissions – empty ?

  8. Pingback: Moving folders via OWA can bypass litigation hold | Blog

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s