Skip to main content

GDPR and your Exchange / Office365 Contacts from a data perspective

GDPR which stands for General Data Protection Regulation is one of those things that surfaces in the IT world (y2k would be another) that seems like a godsend to the lawyers and anybody doing project management.  Endless paperwork, meetings, manual writing and training that seems to achieve little but cost a ton. One of the problems with GDPR is the very broad brush it paints with about what is considered private data and what constitutes compliance. What I'm going to cover in this post is what you can do if your on the receiving end of a GDPR data request around Contacts that are stored in an Exchange Mailbox and how scripting can help you out. I'm not going to talk about any of the legalities around GDPR because its a bit of minefield but look more at it from the data prospective.

Mailbox Contacts

From a strictly data view the majority of properties that make up an Outlook Contact record is private data. Eg a Persons Name, PhoneNumber, Email Address, Address information etc is the data that essentially makes a contact functional. The volume of personal information people will store in contacts is a very personal thing to the Mailbox owner. Eg some people may store the birthday information of a client, spouse or children which Outlook can cater for to provide a more personal touch while for others just the EmailAddress and Name is enough. Contacts folders can then be shared within or outside an organization (policy dependant)which is where you can really start to getting into trouble and is where  IT professionals should have a part to play to ensure that when things are shared that it is done with security and privacy in mind. Data Stewardship is probably a new buzzword you might starting to here more often.

Should GDPR spell the end of using the default standard permission on Contacts folders ?

I'm posing this as a question more then a statement but my thoughts are probably. The default standard permission on a Mailbox Folder basically allows you to specify everyone (has to be an authenticated user with a Mailbox) can access a particular folder in your Mailbox. eg

By default on an Exchange folder this is set to None (so privacy by design would be good) but if a user (or and administrator using a PowerShell script) has set this to anything other then None on Contacts folders then they are basically sharing any private data they have stored in there own mailbox's contacts folder but can't account for who has access to it and in turn how it maybe used. EG a new Intern in the company decides to email everyone in the contacts folder to complete a task they didn't understand etc. Data Stewardship can mean at lot of different things but as a basic one you should know who has access to private data and be able to explain why people have that access and understand the privacy implications of accessing the underlying data. Eg your switching away from doing things for purely convenience.

Reporting on the state of the private data being stored

Reporting on private data can pose some special logical problems in that the report your producing shouldn't expose any of the underlying data your reporting one. One approach is a simple yes/no on which data is being stored or score each data point and provide a report on that. I've written a script that does both and added it to my contacts Module which is available on the PowerShell gallery and GitHub basically what this script does is checks a number of the default contacts properties (not all of them) and counts each one that has data and what data type are available so you can then produce a report of that eg.

This script works in turn with other cmdlets in the Module eg to produce the above report on all contacts in the default Contacts Folder of a Mailbox

$Contacts = Get-EXCContacts -MailboxName -Folder \contacts $Contacts | ForEach-Object{     Get-EXCPrivacyReport -Contact $_ }
You could also do it as a one-liner if you want to limit the report for example to those contacts with Notes eg

 Get-EXCContacts -MailboxName -Folder \contacts  | ForEach-Object{ Get-EXCPrivacyReport -Contact $_ } | where-object {$_.HasNotes -eq $true}
I'm only reporting on certain contact properties so this if you have a request to do this type or reporting I would suggest taking a look at the code which is available on GitHub and customising it to suit whatever your reporting needs are (or hire me and I'll do it as I could use the work at the moment).

Searching for Contacts

Article 17 of GDPR covers the rights to erasure (right to be forgotten), while its probably unlikely that this should ever effect Outlook Contacts it maybe that one day you find yourself being asked to show that you  could comply with such a request.

Generally this means just going in and deleting one contact in the Outlook Contacts folders but if your asked to do this across a number of Mailboxes or the Mailbox has a number of Contacts folders where the contact maybe located (or maybe the user has copied the contacts) this is where some type of automated search can be useful. Usually the first port of call for searching would be either the Search-Mailbox cmdlet or eDiscovery/Compliance tools in Office365 portal or OnPerm server. These currently don't seem to offer the ability to do a simple search via Email Address or DisplayName for an Outlook contact so I've written a script and added this to my EWS Contacts Module that can do this.

This script first gets all the Contacts Folder in a Mailbox in the visible Mailbox Root and then does a KQL (or AQS if you still on 2010) search of each of these Contacts Folder. With this script I do a parameter-less Keyword search of the Contacts which given that the emailaddresses and displayname should be indexed should then return the contacts as need. I then do some validation at the client side to remove any false positives by checking each of the 3 EmailAddress properties if you searched via email address or the many displayName properties that are available. If you are searching by displayName you do need to be careful of the format and any punctuation that maybe have been used that could affect the search results.(if you where requested to search via Telephone number that's possible but each phone number is a different so would require extra code to support that)

The following is an example of using the Search cmdlet to search via email

Search-EXCAllContactFolders -MailboxName -EmailAddress  -Credentials $cred
or to search via displayName

Search-EXCAllContactFolders -MailboxName -DisplayName "user im lookingfor"  -Credentials $cred
This script returns the typed EWS Managed API objects which is useful if you want to do further manipulation (Copy,Move) or if you just want to delete the object just call the Delete Method with the Enumeration for the type of delete you want to do eg for a soft deleted


The other thing the script returns is what property it matched on so for instance if it is the EmailAddress you are searching for and the TargetContact has this email address as its EmailAddress3 property when you look at the results of the search if you check the matched property it will show you this eg

As you can see above I haven't filtered any of the hidden Contact folders in the Mailbox so it will search through some of the System Folders like the Recipient Cache etc.

One last thing to remember here is that if your just talking about the emailaddress of a person its going to be stored in other places in the Mailbox eg AutoComplete Cache and in any email correspondents. So completely forgetting an email address across all dataset in Exchange is extremely impractical. (eg consider that its also held in Tracking logs, Antispam gateways etc).

Contact Groups

Contract Groups are personal distribution lists that are stored in a Mailbox's Contact Folders. From a Search perspective if you where looking to find if an Email Address was a member of any Contact Groups in a Mailbox it not an easy task to fulfil (because there is no mechanism to search contact Group members).So for this I've written a script that will enumerate all the Contact Groups across all Contacts Folders, then enumerate all the members in theses groups and then check each of the EmailAddresses or DisplayName (Email displayname) properties to check if a users is member. This Script will then return the Group if found with a new property call MatchedMember with the Member that was found. This make it easier if you want then remove the member you can call the Member.Remove Method using this property. Eg to find and remove a user from a Contact Group using this cmdlet

$Groups = Search-EXCAllContactGroups -MailboxName -Credentials $cred -EmailAddress Foreach($Group in $Groups){        write-host ("Removing : " + $Group.MatchedMember.AddressInformation.Address + " From " + $Group.DisplayName)        $Group.Members.Remove($Group.MatchedMember)        $Group.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite) }
All the source code for the scripts I've talked about in the post from GitHub here or you can get the Module from the PowerShell Gallery here

Popular posts from this blog

Export calendar Items to a CSV file using EWS and Powershell

Somebody asked about this last week and while I have a lot of EWS scripts that do access the Calendar I didn't have a simple example that just exported a list of the Calendar events with relevant information to a CSV file so here it is. I've talked on this one before in this howto  but when you query the calendar folder using EWS you need to use a CalendarView which will expand any recurring appointments in a calendar. There are some limits when you use a calendarview in that you can only return a maximum of 2 years of appointments at a time and paging will limit the max number of items to 1000 per call. So if you have a calendar with a very large number of appointments you need to break your query into small date time blocks. In this example script I'm just grabbing the next 7 days of appointments if you want to query a longer period you need to adjust the following lines (keeping in mind what I just mentioned) #Define Date to Query $StartDate = (Get-Date) $EndDate

Writing a simple scripted process to download attachmentts in Exchange 2007/ 2010 using the EWS Managed API

Every complicated thing in life is made up of smaller simpler building blocks, when it comes to writing a script (or any code really) the more of these little building blocks you have to figure out the more the process of solving a problem can become bewildering. The Internet generally provides you with lots of half eaten sandwiches of information something someone else has taken a bite out but a lot of the time half done, and as with any code its usefulness declines over time as new and better API's and methods are derived. In this post I'm going to go through a simple scripted process that hopefully covers a few more of these smaller building blocks that you might face when asked to come up with a simple costless solution to perform an automated business function with a script. So the process im going to look at is one that comes up a lot and that is you have an Email that comes into to certain mailbox every day with a certain subject in my case "Daily Export" this

EWS Managed API and Powershell How-To series Part 1

I thought I'd start the year with a series of posts that goes back over the basics of using the EWS Managed API from Powershell and provides a modular remarked example that you can easily cut and paste to build your own scripts. Along the way in this series I'll show a whole bunch of examples around specific things. As a starting point for versions this will be Powershell Version 2.0  and the EWS Managed API 1.1 (which will soon change to 1.2 once released) The starting point for any EWS script your going to write is connecting to Exchange for which there are three important pieces of information you will need. Firstly you need to know the version of Exchange your running in this script its going to be held in the following variable $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1 Other valid values for Exchange 2007 would be $ExchangeVersion = [Microsoft.Exchange.Web
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.