Search This Blog

Thursday 15 October 2015

Getting folder permissions in a multi language environment

I have recently been working with a customer to audit their mailbox delegate permissions ready for a migration to Office 365.  This is because mailbox delegation/permissions don't work cross premises, i.e. the delegates and mailbox owners need to be all on-premise or all in O365.


Scenario

My issue was that this customer has a worldwide presence, and as such the users' mailboxes use a variety of languages.  This causes an issue as get-mailboxfolderpermissions requires the local language version of the folder in order to query permissions, e.g. get-mailboxfolderpermissions "usera:\calendario" to get a Spanish user's calendar permissions.

The usual way around this, which you will find plenty of hits for with your search engine of choice, is to use get-mailboxfolderstatistics to work out the local language name for the folder and then query get-mailboxfolderpermissions with that folder name.  Example code:

$Calendarfolder = $Mailbox.Name + ':\' + [string](Get-MailboxFolderStatistics $Mailbox.Identity | where-object {$_.foldertype -eq "calendar"}).Name 
# Get the permissions on the calendar $CalendarPermissions = Get-MailboxFolderPermission $Calendarfolder
This works really well if all your servers are running the same version of Exchange, albeit rather slowly due to the time taken to execute get-mailboxfolderstatistics. However, the get-mailboxfolderstatistics command can only query mailboxes that match the version of Exchange Server running the command.  Therefore if you run the command on Exchange 2013 against a 2010 mailbox you will get the dreaded wall of red:

>Unable to retrieve mailbox folder statistics for mailbox USERA. Failure: Error code -2146233088 occurred with message The mailbox of user usera@domain.com that is located on a server that is running version 14 can't be opened on a server that is running version 15.. + CategoryInfo : ReadError: (:) [Get-MailboxFolderStatistics], MailboxFolderStatisticsException + FullyQualifiedErrorId : [Server=EXCHANGE-01,RequestId=5787b9cf-9158-4dc4-a1cf-d7b63dd93ca8,TimeStamp=15/10/2015 13:59:37] [FailureCategory=Cmdlet-MailboxFolderStatisticsException] 147CD831,Microsoft.Exchange.Management.Tasks.GetMailboxFolderStatistics + PSComputerName        : exchange-01.domain.com



Resolution

In order to work around this issue, I decided to use EWS to help me resolve the folder's name in the local language so I could then pass it to get-mailboxfolderpermissions.  This initially caused me another challenge, as the customer had self-signed SSL certificates in use on the server which by default EWS doesn't like.

This code can be found easily on the web to bypass the SSL error (courtesy of http://poshcode.org/624):

$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider $Compiler=$Provider.CreateCompiler() $Params=New-Object System.CodeDom.Compiler.CompilerParameters $Params.GenerateExecutable=$False $Params.GenerateInMemory=$True $Params.IncludeDebugInformation=$False $Params.ReferencedAssemblies.Add("System.DLL") | Out-Null $TASource=@' namespace Local.ToolkitExtensions.Net.CertificatePolicy{ public class TrustAll : System.Net.ICertificatePolicy {       public TrustAll() {       }       public bool CheckValidationResult(System.Net.ServicePoint sp,         System.Security.Cryptography.X509Certificates.X509Certificate cert,         System.Net.WebRequest req, int problem) {         return true;       }     } } '@ $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource) $TAAssembly=$TAResults.CompiledAssembly # We now create an instance of the TrustAll and attach it to the ServicePointManager $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll") [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll # End self-signed cert ignore code block
Once that SSL error was out of the way, I could turn my attention to using EWS to enumerate the folder names for me in the local language. You will need the EWS Managed API (2.2 is current at time of writing) and also the account under which you run the script will need impersonation rights. Code to grant impersonation rights can be found at the end of this post.
# Specify target mailbox's SMTP address  $mailbox = "SpanishUser@Domain.com" # Specify the well known folder (inbox,calendar,contacts,tasks,sentitems,deleteditems etc.) $folder = "inbox" # Specify minimum version of Exchange that EWS will support $exchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2 # Create a new service connection to EWS $exchService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($exchangeVersion) # Use the credentials of the logged in user $exchService.UseDefaultCredentials = $true # Use Exchange impersonation $exchService.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$mailbox) # Use autodiscover against target mailbox to find the EWS URL $exchService.AutodiscoverUrl($mailbox ) # Get the well known folder's ID $folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::$folder,$mailbox)   # Bind the folder ID to the EWS Service and store in a variable $FolderProperties = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Exchservice,$folderid# The displayname property gives us the local language name to use against get-mailboxfolderpermissions $FolderProperties.displayname
Here is the output of the above command for a Spanish user. The important bit is in bold:
Id                       : AAAACRPjqCeKsySbFqTI7GG9YjAQBXlKebj99ISaYHYuUfYkGcAAAAAAEMAAA=
ParentFolderId           : AAMkAGRmMDZjY2E0LTlhMzgtNGNkYy04ODE5LWJlNWY2ZGM3NDySbFqTI7GG9YjAQBXlKeb
ChildFolderCount         : 0
DisplayName            : Bandeja de entrada
FolderClass              : IPF.Note
TotalCount               : 0
ExtendedProperties       : {}
ManagedFolderInformation :
EffectiveRights          : CreateAssociated, CreateContents, CreateHierarchy, Delete, Modify, Read, ViewPrivateItems
Permissions              : {}
UnreadCount              : 0
PolicyTag                :
ArchiveTag               :
WellKnownFolderName      :
Schema                   : {Id, ParentFolderId, FolderClass, DisplayName, TotalCount, ChildFolderCount,
Service                  : Microsoft.Exchange.WebServices.Data.ExchangeService
IsNew                    : False
IsDirty                  : False
We can now use the displayname found about to request folder permissions, e.g:
get-mailboxfolderpermissions "usera:\Bandeja de entrada"
To grant the impersonation rights required above, use the following command (you may have to restart the PowerShell session afterwards):
New-ManagementRoleAssignment –Name:impersonationAssignmentName –Role:ApplicationImpersonation –User:<UserToBeGivenRights>

No comments:

Post a Comment