When you migrate messages from an alternative email solution (e.g. Lotus Notes) you might migrate sensitive content that must stay private in the new Exchange Server target location.
So how can you mark such messages as private?
The privacy level (Sensitivity) of a mailbox item is controlled by MAPI extended property 0x36.
The command line tool searches for messages containing a given text as a subject substring.
The c# code sets the extended property 0x36 to 2.
A mailbox is accessed using Exchange Web Services. The EWS endpoint is discovered using AutoDiscover for the selected mailbox.
The item modification is handled by the following code segment:
foreach (var extendedProperty in Message.ExtendedProperties) { if (extendedProperty.PropertyDefinition == extendedPropertyDefinition) { if (log.IsInfoEnabled) { log.Info(string.Format("Try to alter the message: {0}", Message.Subject)); } else { Console.WriteLine("Try to alter the message: {0}", Message.Subject); } // Set the value of the extended property (0 is Sensitivity normal, 2 would be private) Message.ExtendedProperties[extendedPropertyindex].Value = 2; // Update the item on the server with the new client-side value of the target extended property Message.Update(ConflictResolutionMode.AlwaysOverwrite); } extendedPropertyindex++; }
SetPrivateFlags.exe -mailbox user@domain.com -subject "[private]"
Search the mailbox for all messages having a subject string containing [private] and ask for changing each item if -logonly is not set to true. If -logonly is set to true only a log will be created.
SetPrivateFlags.exe -mailbox user@domain.com -subject "[private]" -noconfirmation
Search the mailbox for all messages having a subject string containing [private] and change all found messages without confirmation.
It should be noted that this solution is intended for use in migration scenarios.
When providing access to mailbox delegates you can enable access to your private elements as well. But access to shared mailboxes is not configured using the delegation workflow.
The code has been tested using Exchange Server 2013 CU15.
The program utilizes log4net to log detailed information to the file system. The configuration is controlled by the application's config file.
Any issues or feature requests? Use Github.
Like the code? Leave a note.
You implement shared mailboxes as part of a legacy public folder migration. Access to the shared mailbox provided by dedicated security groups which, in this case, provide access to dedicated sub folders within the mailbox.
The migrated legacy public folder content contained items marked as private.
When you access a shared mailbox as a group member you are not able to see or access private items.
The following two screenshots are used to demontraste the issue:
The Inbox node shows three unread items:
The Inbox detail pane just shows a single read message:
So how to access items marked as private?
When an item does have an extended property 0x36, the value is set to 0.
The item modificatiuon is handled by the following code segment:
var extendedPropertyDefinition = new ExtendedPropertyDefinition(0x36, MapiPropertyType.Integer); int extendedPropertyindex = 0; foreach (var extendedProperty in Message.ExtendedProperties) { if (extendedProperty.PropertyDefinition == extendedPropertyDefinition) { if (log.IsInfoEnabled) { log.Info(string.Format("Try to remove private flag from message: {0}", Message.Subject)); } else { Console.WriteLine("Try to remove private flag from message: {0}", Message.Subject); } // Set the value of the extended property to 0 (which is Sensitivity normal, 2 would be private) Message.ExtendedProperties[extendedPropertyindex].Value = 0; // Update the item on the server with the new client-side value of the target extended property. Message.Update(ConflictResolutionMode.AlwaysOverwrite); } extendedPropertyindex++; }
RemovePrivateFlags.exe -mailbox user@domain.com [-logonly] [-foldername "Inbox"]
Search through the mailbox and ask for changing a item if -logonly is not set to true. If -foldername is given the folder path are compared to the folder name. If -logonly is set to true only a log will be created.
RemovePrivateFlags.exe -mailbox user@domain.com [-foldername "Inbox"] [-noconfirmation]
Search through the mailbox, if -noconfirmation is set to true all items will be altered without confirmation.
When providing access to mailbnox delegates you can enable access to your private elements as well. But access to shared mailboxes is not configured using the delegation workflow.
This script removes Active Directory objects for HealthMailboxes or SystemMailboxes in the Microsoft Exchange System Objects (MESO) container that do not have a homeMDB attribute set.
It is highly recommended to run the script with -WhatIf parameter to check objects first.
Information about accounts deleted or supposed to be deleted are written to a log file.
# EXAMPLE # Perform a WhatIf run in preparation to removing SystemMailboxes having an empty database attribute .\Remove-OrphanedMailboxAccounts.ps1 -SystemMailbox -WhatIf # EXAMPLE # Remove HealthMailbox(es) having an empty database attribute .\Remove-OrphanedMailboxAccounts.ps1 -HealthMailbox
2017-02-10 10:18: 11488 - Info - Script started 2017-02-10 10:18: 11488 - Info - WhatIf Preference: True 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | 10 objects found 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailboxd32b165a6adf45518c8498fba3c7c93a,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailbox6b66930902d8430e831df7b086bfd49b,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailbox6bf99bdc31474217a6fdc4cd83260e88,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailboxd4410bf131b34907b6a96a7e65263db1,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailbox98f334580dbf457ca2a6d1a19fdf49d1,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailboxc16704bf98c94f5e8453c7955d7897b5,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailboxa64fe085bdff46a786d68782c5070bf1,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailbox6c56f94506974a1183c6b71eebb63406,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailbox9b6666d46aa746e3848f3240e418d731,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Cleaning HealthMailboxes | Delete CN=HealthMailboxb2bd3d4725b249bab81eeed35666de0f,CN=Monitoring Mailboxes,CN=Microsoft Exchange System Objects,DC=granikoslabs,DC=de 2017-02-10 10:18: 11488 - Info - Script finished
This is a post summarizing the configuration values for important Exchange-related Active Directory object attributes.
Whenever you need to look up these values for troubleshooting, or editing the values manually.
Attribute
Migrating legacy public folders (Exchange Server 2010 or older) to modern public folders (Exchange 2013 or newer / Office 365) requires a cleanup of public folders.
There are quite a lot of blog posts and tutorials available describing the general process of migrating legacy public folders to modern public folders.
First you have to identify all public folders having a backslash "\" as part of the public folder name.
Get-PublicFolderDatabase | ForEach {Get-PublicFolderStatistics -Server $_.Server | Where {$_.Name -like "*\*"}}
Just rename those public folders to a name without a backslash.
Another issue might prevent a successful public folder migration: Access Controll Lists (ACL)
This will be the case in public folder hierarchies that go back to the early days of Exchange and have never cleaned up properly during past Exchange migrations.
The cleanup any orphaned Active Directory accounts, run the following PowerShell script.
Get-PublicFolder "\" -Recurse -ResultSize Unlimited | Get-PublicFolderClientPermission | ?{$_.User -like "NT User:S-1-*"} | %{Remove-PublicFolderClientPermission -Identity $_.Identity -User $_.User -Access $_.AccessRights -Confirm:$false}
To cleanup just a single public folder, run the following PowerShell script.
Get-PublicFolder "\My Folder" -Recurse -ResultSize Unlimited | Get-PublicFolderClientPermission | ?{$_.User -like "NT User:S-1-*"} | %{Remove-PublicFolderClientPermission -Identity $_.Identity -User $_.User -Access $_.AccessRights -Confirm:$false}
It should be noted that most of the tutorials have been written using an Exchange Server lab environment with just a few legacy public folders. Therefore, some readers tend to beleive that you only need one modern public folder mailbox. That is not true. In a large legacy public folder infrastructure you will end up with a multiple public folder mailboxes. And the number of mailboxes required to serve the public folder hierarchy.
A larger public folder migration batch using 66 public folder mailboxes looks like this:
Get-MigrationUser -BatchID PFMigration | Get-MigrationUserStatistics | ft -AutoSize Identity Batch Status Items Synced Items Skipped -------- ----- ------ ------------ ------------- PFMailbox1 PFMigration Synced 91993 16 PFMailbox2 PFMigration Synced 103239 0 PFMailbox46 PFMigration Synced 35034 0 PFMailbox56 PFMigration Synced 22554 0 PFMailbox57 PFMigration Synced 20740 0 PFMailbox58 PFMigration Synced 20122 0 PFMailbox59 PFMigration Synced 7209 0 PFMailbox60 PFMigration Synced 104727 0 PFMailbox61 PFMigration Synced 23278 0 PFMailbox62 PFMigration Synced 9760 0 PFMailbox63 PFMigration Synced 9277 0 PFMailbox65 PFMigration Synced 5870 0 PFMailbox64 PFMigration Synced 5639 0 PFMailbox66 PFMigration Synced 21261 0 PFMailbox50 PFMigration Synced 27889 0 PFMailbox52 PFMigration Synced 14063 0 PFMailbox47 PFMigration Synced 29476 0 PFMailbox54 PFMigration Synced 24283 0 PFMailbox55 PFMigration Synced 4646 0 PFMailbox51 PFMigration Synced 59943 0 PFMailbox53 PFMigration Synced 30052 0 PFMailbox49 PFMigration Synced 22746 0 PFMailbox48 PFMigration Synced 16941 0 PFMailbox18 PFMigration Synced 34307 0 PFMailbox19 PFMigration Synced 4523 0 PFMailbox11 PFMigration Synced 100409 0 PFMailbox6 PFMigration Synced 116655 0 PFMailbox4 PFMigration Synced 55240 5 PFMailbox12 PFMigration Synced 37790 0 PFMailbox3 PFMigration Synced 113842 2 PFMailbox22 PFMigration Synced 46416 0 PFMailbox23 PFMigration Synced 37387 0 PFMailbox13 PFMigration Synced 231845 1 PFMailbox7 PFMigration Synced 82859 0 PFMailbox20 PFMigration Synced 65818 0 PFMailbox21 PFMigration Synced 32270 0 PFMailbox9 PFMigration Synced 46609 0 PFMailbox14 PFMigration Synced 30637 0 PFMailbox38 PFMigration Synced 246428 1 PFMailbox43 PFMigration Synced 101837 0 PFMailbox45 PFMigration Synced 157571 0 PFMailbox44 PFMigration Synced 61763 0 PFMailbox40 PFMigration Synced 70637 1 PFMailbox41 PFMigration Synced 143042 0 PFMailbox42 PFMigration Synced 81254 0 PFMailbox39 PFMigration Synced 68876 2 PFMailbox15 PFMigration Synced 58221 0 PFMailbox27 PFMigration Synced 28065 0 PFMailbox24 PFMigration Synced 31869 1 PFMailbox5 PFMigration Synced 64125 0 PFMailbox30 PFMigration Synced 72938 1 PFMailbox33 PFMigration Synced 32545 1 PFMailbox31 PFMigration Synced 93782 0 PFMailbox32 PFMigration Synced 28743 0 PFMailbox25 PFMigration Synced 100794 0 PFMailbox26 PFMigration Synced 35412 0 PFMailbox28 PFMigration Synced 27003 0 PFMailbox29 PFMigration Synced 80510 0 PFMailbox17 PFMigration Synced 97952 1 PFMailbox8 PFMigration Synced 18601 0 PFMailbox34 PFMigration Synced 87150 0 PFMailbox35 PFMigration Synced 31531 0 PFMailbox36 PFMigration Synced 37979 0 PFMailbox37 PFMigration Synced 95770 0 PFMailbox10 PFMigration Synced 14193 0 PFMailbox16 PFMigration Synced 64323 1
Enjoy (modern) public folders.
You need assistance with your Exchange Server setup? You have questions about your Exchange Server infrastructure and going hybrid with Office 365? Contact us at office365@granikos.eu or visit our website https://www.granikos.eu.
When you delete a mailbox or an Active Directory account, the soft-deleted or disconnected mailbox won't show up in the list of disconnected mailboxes immediately. The mailbox status is updated as part of a mailbox store maintenance task.
When you query a mailbox database for disconnected mailboxes you will find a mailbox having the DisconnectReason and DisconnectDate attribute empty.
# Query the mailbox using the original user display name Get-MailboxDatabase | Get-MailboxStatistics | Where { $_.DisplayName -eq "LASTNAME, FIRSTNAME" } | fl DisconnectReason,DisconnectDate,MailboxGuid,Database # Use wildcards if the correct display name is unknown Get-MailboxDatabase | Get-MailboxStatistics | Where { $_.DisplayName -like "*LASTNAME*" } | fl DisconnectReason,DisconnectDate,MailboxGuid,Database DisconnectReason : DisconnectDate : MailboxGuid : a04a8aab-c360-406b-a194-8c290d56668b Database : MBXDB34
You can find disonnected mailboxes by
The following PowerShell cmdlet updates the mailbox state of a single mailbox using the MailboxGuid as an identifier.
Update-StoreMailboxState -Database MBXDB34 -Identity a04a8aab-c360-406b-a194-8c290d56668b
After updating the mailbox state the DisconnectReason and DisconnectDate attributes are properly set.
Get-MailboxDatabase | Get-MailboxStatistics | Where { $_.DisplayName -eq "LASTNAME, FIRSTNAME" } | fl DisconnectReason,DisconnectDate,MailboxGuid,Database DisconnectReason : Disabled DisconnectDate : 01.01.2017 15:02:59 MailboxGuid : a04a8aab-c360-406b-a194-8c290d56668b Database : MBXDB34
The disconnected mailbox is now visible in Exchange Administrative Center (EAC) and can be reconnected using EAC or Exchange Management Shell.
By default a disconnected mailbox is supposed to be connected it's original account having a matching LegacyExchangeDN attribute. Connecting the mailbox to a different Active Directory account requires the use of the AllowLegacyDNMismatch parameter.
# Connect a mailbox to the original AD account having a matching LegacyExchangeDN Connect-Mailbox -Database MBXDB34 -Identity "Doe, John" # Connect a mailbox to a different AD account Connect-Mailbox -Database MBXDB34 -Identity "Doe, John" -User "Jane Doe" -AllowLegacyDNMismatch
Examples for room and shared mailboxes are described in the Connect-Mailbox documentation.
When you run your Exchange Organization in hybrid mode with Office 365 and you migrate your on-premise Public Folders to Office 365, you are required to configure a remote Public Folder Mailbox in the Exchange Organization settings.
With Public Folders on-premise your Exchange Online Org looks like this:
Get-OrganizationConfig | fl *public* DefaultPublicFolderAgeLimit : DefaultPublicFolderIssueWarningQuota : 1.7 GB (1,825,361,920 bytes) DefaultPublicFolderProhibitPostQuota : 2 GB (2,147,483,648 bytes) DefaultPublicFolderMaxItemSize : Unlimited DefaultPublicFolderDeletedItemRetention : 30.00:00:00 DefaultPublicFolderMovedItemRetention : 7.00:00:00 PublicFoldersLockedForMigration : False PublicFolderMigrationComplete : False PublicFoldersEnabled : Remote PublicComputersDetectionEnabled : False RootPublicFolderMailbox : 00000000-0000-0000-0000-000000000000 RemotePublicFolderMailboxes : {PublicFolder-Mailbox001}
With Public Folders on-premise your On-Premise Exchange Org looks like this:
Get-OrganizationConfig | fl *public* DefaultPublicFolderAgeLimit : DefaultPublicFolderIssueWarningQuota : Unlimited DefaultPublicFolderProhibitPostQuota : Unlimited DefaultPublicFolderMaxItemSize : Unlimited DefaultPublicFolderDeletedItemRetention : 30.00:00:00 DefaultPublicFolderMovedItemRetention : 7.00:00:00 PublicFoldersLockedForMigration : True PublicFolderMigrationComplete : True PublicFoldersEnabled : Local PublicComputersDetectionEnabled : False RootPublicFolderMailbox : ae0ef819-90d2-45d0-92b6-8b2062cf71a3 RemotePublicFolderMailboxes : {}
With Public Folders in Exchange Online your Exchange Online Org looks like this:
Get-OrganizationConfig | fl *public* DefaultPublicFolderAgeLimit : DefaultPublicFolderIssueWarningQuota : 1.7 GB (1,825,361,920 bytes) DefaultPublicFolderProhibitPostQuota : 2 GB (2,147,483,648 bytes) DefaultPublicFolderMaxItemSize : Unlimited DefaultPublicFolderDeletedItemRetention : 30.00:00:00 DefaultPublicFolderMovedItemRetention : 7.00:00:00 PublicFoldersLockedForMigration : False PublicFolderMigrationComplete : False PublicFoldersEnabled : Local PublicComputersDetectionEnabled : False RootPublicFolderMailbox : 5810bb30-cdda-4287-85a4-8a2547bb9b01 RemotePublicFolderMailboxes : {}
With Public Folders in Exchange Online your Exchange On-Premise Org looks like this:
Get-OrganizationConfig | fl *public* DefaultPublicFolderAgeLimit : DefaultPublicFolderIssueWarningQuota : Unlimited DefaultPublicFolderProhibitPostQuota : Unlimited DefaultPublicFolderMaxItemSize : Unlimited DefaultPublicFolderDeletedItemRetention : 30.00:00:00 DefaultPublicFolderMovedItemRetention : 7.00:00:00 PublicFoldersLockedForMigration : True PublicFolderMigrationComplete : True PublicFoldersEnabled : Remote PublicComputersDetectionEnabled : False RootPublicFolderMailbox : 00000000-0000-0000-0000-000000000000 RemotePublicFolderMailboxes : {mcsmemail.de/Users/PF365-Mailbox-01-55e3d544-ed5a-4557-9008-d8c1b6f06d86}
The remote public folder mailbox has been added to the on-premise Exchange confguration by using:
Set-OrganizationConfig -RemotePublicFolderMailboxes PF365-Mailbox-001 -PublicFoldersEnabled Remote
To be able to add the remote public folder mailbox in a hybrid configuration you are required to add the public folder mailbox (or mailboxes, if you have more than one serving the hierarchy) as a mail user.
Microsoft provides a PowerShell script as part of a script collection here.
When you run the Import-PublicFolderMailboxes.ps1 script you might run into the following error:
Cannot bind parameter 'Name' to the target. Exception setting "Name": "The length of the property is too long. The maximum length is 64 and the length of the value provided is 65." + CategoryInfo : WriteError: (:) [New-MailUser], ParameterBindingException + FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.Exchange.Management.RecipientTasks.NewMailUser + PSComputerName : ex2013.mcsmemail.de
The name attribute for a mail user is limited to 64 characters. But why are you exceeding the length when the mailbox name is only 17 characters long?
It turns out that the PowerSheel script adds a prefix name "" and ther mailbox GUID as a suffix. And voilá, the name exceeds the allowed length for the mail user name attribute.
Don't use more than 16 characters when naming the Public Folder mailboxes in Office 365.
Or modify the Import-PublicFolderMailboxes.ps1 script to fit your needs.
$hasPublicFolderServingHierarchy = $true; $displayName = $publicFolderMailbox.Name.ToString().Trim(); # ORIG: $name = "RemotePfMbx-" + $displayName + "-" + [guid]::NewGuid(); $name = $displayName + "-" + [guid]::NewGuid(); $externalEmailAddress = $publicFolderMailbox.PrimarySmtpAddress.ToString();
You need assistance with your Exchange Server setup? You have questions about your Exchange Server infrastructure and going hybrid? You are interested in what Exchange Server 2016 has to offer for your environment? Contact me at thomas@mcsmemail.de Follow at https://twitter.com/stensitzki