Skip to main content

Class library helper for setting Calendar Permission via Powershell and Exchange 2007

I posted something a while ago that tried to explain how you can go about setting calendar rights using the new features in EWS included in Exchange 2007 SP1. Unfortunately from the feedback i got it seemed to confuse people more than help it seemed most people where interested in resetting the default calendar permissions especially in regards to the new Freebusy Acl’s that where included in Exchange 2007/Outlook 2007. The freebusy rights pose a special challenge because the normal scripts like CDO 1.2 or Pfdavadmin can’t be used to set these particular rights you need to use either the Outlook 2007 OOM or EWS. So I decided to come up with a helper class similar to the OOF helper class I wrote before that would allow people to change the rights on a calendar just using a couple of lines in Powershell.

Because I already has a namespace for the OOF helper I decided to fork that code into a new namespace and library and I thought that I’d be able to reuse a lot of what I’d done before.... But the library turned out to be a lot more complex to get working for a number of reasons and required a lot of extra logic to get the library to behave the way I wanted to (but hey go hard or go home). How does it work well lets take a walk though and I’ll try to explain. Firstly if you want to use the library in Powershell you need to load it with a cmd such as

[void][Reflection.Assembly]::LoadFile("c:\temp\EWSUtil.dll")

Then you can actually create an object using the class library you just loaded when you create the object you need to specify some parameters that will be used to query EWS. The only mandatory parameter is the email address the optional parameters control how the object will work with EWS and how it handles authentication and which CAS it will use. The first parameter is the impersonation parameter which is a Boolean that controls whether the object will use EWS impersonation to access mailboxes or just use Delegate access (when I talk about delegate access I don’t mean delegated Exchange Admin access I mean either Outlook delegates or rights assigned via add-mailboxpermission). EWS impersonation comes in handy and is a more secure way of giving rights to an account to do a job such as changing calendar rights for every use on a server see http://msdn2.microsoft.com/en-us/library/bb204095.aspx for giving an account EWS impersonation rights.

The next three parameters are for the username,password and domain if you want to specify the user context you want this object to run under. This allows you to use this library on a machine that isn’t a member of the domain or run the library as a user that’s different from the currently logged on user. The last parameter is for the URL of the CAS Server to use this is important if you want to run the script from a machine that isn’t a member of the domain the Exchange Server is a member of. By default if you don’t specify this value the Library will try to look up active directory for the autodiscovery address and then try to do a Autodiscover request to find the EWS url based on the email address entered. Once you have everything worked out you need to run a line like this to create a calendar utility object.

$calutil = new-object EWSUtil.CalendarUtil("fred@domain.com", $false, "admin", "password#", "domain", "https://servername /EWS/Exchange.asmx")

Issuing this command will cause the GetFolder request to be issued to the server and it will retrieve the current calendar folder permissions and populate a generic list of Calendarpermssion objects.

This is where we encounter our first caveat as I said in a previous post the permission roles you set in Outlook don’t reflect the permissions level returned by EWS. So for most of the Outlook Roles you set you would see that as a custom permission in EWS (apart from FreeBusy rights which are reflected correctly). To work around this I created a few helper routines to convert the custom permissions that EWS returns back to the appropriate Outlook Roles which is handy if you’re trying to document or check the permissions that have been set via Outlook. And also some helpers so when you want to set permissions instead of using the EWS calendar permission that will be reflected as Custom permissions when viewed in Outlook you will see the correct Outlook role set. This is a hard one to explain its just one of the current nuances of EWS. An example of using one of the helper routines to set an ACE to an outlook role for a user your adding to the calendar DACL you would need to use one of the following lines depending on the Outlook Role you wanted to set.

$calutil.CalendarDACL.Add($calutil.NonePermissions(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.FreeBusyTimeOnly(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.FreeBusyTimeAndSubjectAndLocation(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.Reviewer(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.Contributer(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.AuthorPermissions(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.NonEditingAuthorPermissions(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.PublishingAuthorPermissions(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.AuthorPermissions(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.EditorPermissions(“user@domain.com”))
$calutil.CalendarDACL.Add($calutil.PublishingEditorPermissions(“user@domain.com”))

If you want to set permissions for the default user or anonymous user on the calendar instead of specifying the email address of the user you need to just put default or anonymous

eg $calutil.CalendarDACL.Add($calutil.FreeBusyTimeAndSubjectAndLocation(“default”))

Once you have added or removed the ACE you wanted to you then just call the update method eg

$Calutil.update()

Another quick sample if you want to output the default permissions and anonymous permission for a users calendar you can do the following. This shows an example of using the enumOutlook helper to get the Outlook Role that has been set.

[void][Reflection.Assembly]::LoadFile("c:\EWSUtil.dll")
$calutil = new-object EWSUtil.CalendarUtil("user@domain.com", $false, "user", "password", "domain", "https://servername/EWS/Exchange.asmx");
for ($cpint=0;$cpint -lt $calutil.CalendarDACL.Count; $cpint++){
if ($calutil.CalendarDACL[$cpint].UserId.DistinguishedUserSpecified -eq $true){
if ($calutil.CalendarDACL[$cpint].UserId.DistinguishedUser -eq [EWSUtil.EWS.DistinguishedUserType]::Default){
"Default " + $calutil.enumOutlookRole($calutil.CalendarDACL[$cpint])
}
if ($calutil.CalendarDACL[$cpint].UserId.DistinguishedUser -eq [EWSUtil.EWS.DistinguishedUserType]::Anonymous){
"Anonymous " + $calutil.enumOutlookRole($calutil.CalendarDACL[$cpint])
}
}

}

A few things about the update method when update is called it will first loop through the generic ACE list and build a Calendarpermission set to be used in a EWS update folder operation. Because there are no verification routines in the List add methods it will go through and make sure you don’t have any duplicate ACE's in the list say if you wanted to set the default permission on a calendar and instead of changing the current ACE you just added a new ACE for the default user. The update routine will find the duplicate ACE's and will use the last one added to the list which will overwrite the old ACE.

To demonstrate the use of this library I’ve put together a little powershell GUI script the will allow you to enumerate all the Default calendar permissions for every user on a server and set them to something else if you so desire. I’ve posted this separately here.

I wish I had more time to document this properly and I will try to update this post when I can. The code itself is very untested and I don’t consider it stable and or safe for use in a production environment I can only recommend that you use it in a test/dev environment and as a guide to building your own applications. I’ve include a complied DLL as well as the full source so you can look/debug as you please. If you do spot any major bugs and things I’ve done wrong or that could be done better please let me know so I can update the source.

I’ve put a download of the source and dll here the update function looks like

Additional -- Added after problems dicovered

One important and potentially frustrating point for anybody who wants to set permissions on the calendar folder in a mailbox with any Exchange API that allows you to modify the folder DACL’s is that you also need add the same ACE your adding (or modifying) to the FreeBusy Data folder which is one the NON_IPM_Subtree Root folders in a mailbox explained in this KB. Exchange Web Services is no exception to this rule and accessing the NON_IPM_Subtree folders isn’t as straight forward as normal mailbox folders but here’s a method for accessing the freebusy folder and modifying the DACL.

So what happens now when you create the object the code will try to retrieve the free/busy folder rights and a separate generic list object is created that contains the current Free/busy folder ACE's called FreeBusyDACL. Because as i said with this DACL you need to use a different type of ACE their are separate ACE objects defined eg

$calutil.FreeBusyDACL.Add($calutil.FolderEmpty(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderReviewer(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderContributer(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderAuthorPermissions(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderNonEditingAuthorPermissions(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderPublishingAuthorPermissions(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderAuthorPermissions(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderEditorPermissions(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderPublishingEditorPermissions(“user@domain.com”))

What you will need to do is duplicate any operations that Add or Remove ACE's to the CalendarDACL to also now do the FreeBusyDACL eg

$calutil.CalendarDACL.Add($calutil.EditorPermissions(“user@domain.com”))
$calutil.FreeBusyDACL.Add($calutil.FolderEditorPermissions(“user@domain.com”))

When you run the update method it will update both DACL's

Popular posts from this blog

Testing and Sending email via SMTP using Opportunistic TLS and oAuth in Office365 with PowerShell

As well as EWS and Remote PowerShell (RPS) other mail protocols POP3, IMAP and SMTP have had OAuth authentication enabled in Exchange Online (Official announcement here ). A while ago I created  this script that used Opportunistic TLS to perform a Telnet style test against a SMTP server using SMTP AUTH. Now that oAuth authentication has been enabled in office365 I've updated this script to be able to use oAuth instead of SMTP Auth to test against Office365. I've also included a function to actually send a Message. Token Acquisition  To Send a Mail using oAuth you first need to get an Access token from Azure AD there are plenty of ways of doing this in PowerShell. You could use a library like MSAL or ADAL (just google your favoured method) or use a library less approach which I've included with this script . Whatever way you do this you need to make sure that your application registration  https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Graph is limited to a m
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.