Subscribe: Glen's Exchange Dev Blog
http://gsexdev.blogspot.com/feeds/posts/default
Added By: Feedage Forager Feedage Grade A rated
Language: English
Tags:
api  ews  exch rest  exchange  folder  https  items  mailbox  mailboxname  microsoft  module  new  office  rest api  rest 
Rate this Feed
Rate this feedRate this feedRate this feedRate this feedRate this feed
Rate this feed 1 starRate this feed 2 starRate this feed 3 starRate this feed 4 starRate this feed 5 star

Comments (0)

Feed Details and Statistics Feed Statistics
Preview: Glen's Exchange Dev Blog

Glen's Exchange Dev Blog



Pushing the Envelope in Messaging Development



Updated: 2018-04-20T19:37:04.184+10:00

 



Generic Toolbox script for using EWS to enumerate Folders and Items in an Exchange Mailbox

2018-04-17T15:32:31.299+10:00

There's a old saying that a tradesmen is only as good as their tools and the same can be said for ITPro's and developers. You can save yourself a lot of time when investigating particular tasks you want a script by having something ready built that can do 90% of task at hand.  I've decided to share a script that I use quite often during the investigation phase of any EWS scripting tasks that allows you to generically grab a folder (or collection of Folders) and the Items within those folder. While this is something that can be put together quite quickly together using snippets there always tends to be extra properties that you need for different tasks so the generic script I'm showing today includes all the niceties kind of like having the right sized spanner rather the shifter.So the script in question can be found on GitHub here https://github.com/gscales/Powershell-Scripts/blob/master/GenericFolderAndItem.ps1So what can it doConnect and show the properties on a Mailbox Folder egInvoke-GenericFolderConnect -MailboxName mailbox@domain.com -FolderPath \Inbox -Credentials $credSo in the above example this is my Inbox, some of the extra things I've added in this script over what you would normally see in EWS is to promote the ExtendedProperties for the retentionTags,FolderSize,FolderPath and AttachmentCount to first class folder properties on the object so they are much easy to first view but to also script on top off. Eg say I only want to look at the Inbox and Subfolders of the Inbox there where larger then 10 MB I can do the followingInvoke-GenericFolderConnect -MailboxName gscales@datarumble.com -FolderPath \Inbox -Credentials $cred  -Recurse | Where-Object{$_.FolderSize -gt 10mb} | select FolderPath,FolderSizeThe above examples uses the -Recurse switch parameter of the script to recurse Subfolders of the pass in folder Path you connected to and then makes use of those promoted properties using the pipeline and Where-Object in PowerShell.One other thing I've added to the Standard EWS FolderObject is the GetLastItem ScriptMethod which does what is says by getting the last item in a folder. For example if I wanted to get the Last Item in My Inbox I could use the followingI could use this method in a recursion as well to show me all the folders in my mailbox that have received a Mail in the last week egInvoke-GenericFolderConnect -MailboxName gscales@datarumble.com -RootFolder -Credentials $cred -Recurse | Where-Object{$_.GetLastItem().DateTimeReceived -gt (Get-Date).AddDays(-7)} | Select-Object FolderPath,FolderSize,@{Name="DateTimeReceived"; Expression = {$_.LastItem.DateTimeReceived}},@{Name="Subject"; Expression = {$_.LastItem.Subject}})}Enumerating FolderItemsAs I've show above getting the Last Item in a folder can be useful but a lot of the time you will want to enumerate all the Items with a folder (or a least the Top X) to do particular reporting or investigation tasks. To do you use the following generic function which will give you back all the items in the Inbox.Invoke-GenericFolderItemEnum -MailboxName gscales@datarumble.com -FolderPath \Inbox -Credentials $credsTo  limit the results to just the top 10 items in the Folder use the -MaxCount switch egInvoke-GenericFolderItemEnum -MailboxName gscales@datarumble.com -FolderPath \Inbox -Credentials $creds -MaxCount 10EWS by default only returns certain properties while doing an item enumeration (using findItems) so things like the Recipients and the Message body wont be returned by default for performance reasons. If you wanted to view these properties on a Message you could use the Load() method on the Message itself or you can use the -FullDetails Switch which will batch these operations which will make it perform better if you have a large number of items that you wish to do this on. Eg to show the last 10 messages in the Inbox with FullDetailsInvoke-GenericFolderItemEnum -MailboxName gscales@datarumble.com -FolderPath \Inbox -Credentials $creds -MaxCount 10 -FullDetailsIf you want to recurse though Subfolders eg to show the top 5 messages fo[...]



Using the Office365/Exchange 2016 REST API in Powershell Contacts

2018-03-23T15:56:55.759+11:00

Within a Mailbox from an API perspective the big 3 things you deal with are first Messaging, second Calendaring and then Contacts. Up until now I've had just some basic support for Contacts in the Exch-Rest module https://www.powershellgallery.com/packages/Exch-Rest but from version 3.4 I've add lot more cmdlets to fill out this functionally. I've taken a guide from my EWSContacts Module and taken advantage of some of the new stuff you can do with the Graph API which was hard or not possible in EWS like getting Mail Enabled Contacts (AD Contacts). I've added a documentation page with Examples on GitHub for most of the new cmdlets https://github.com/gscales/Exch-Rest/blob/master/Samples/ContactsExamples.mdTo give a little taste of what you can do with these new cmldetsCreating ContactsThe New-EXRContact cmdlet can be used to create a contact in any mailbox specifying the most common propertiesNew-EXRContact -MailboxName mec@datarumble.com -FirstName "FirstName" -LastName "Surname of Contact" -EmailAddress "EmailAddress@domain.com" -MobilePhone 1111-222-333If you want to also upload a photo as part of the contact you can use -photo switch to specify a file-name that contains the contact photo you want to be used for that contact egNew-EXRContact -MailboxName mec@datarumble.com -FirstName "FirstName" -LastName "Surname of Contact" -EmailAddress "EmailAddress@domain.com" -MobilePhone 1111-222-333 -photo 'c:\photo\Johnsmith.jpg'To create a contact in a contact Folder other then the default in the Mailbox useNew-EXRContact -MailboxName mec@datarumble.com -FirstName "FirstName" -LastName "Surname of Contact" -EmailAddress "EmailAddress@domain.com" -MobilePhone 1111-222-333 -ContactFolder SubContactFolderModifying existing ContactsEg modifying the department filed of an existing contact first find the contact based on the Email address and then update the Department field$ExistingContact = Search-EXRContacts -MailboxName user@domain -emailaddressKQL 'myaddress@domain.com' Set-EXRContact -Id $ExistingContact.id -Department "New Department"Uploading a Contact Photo of an existing contact$ExistingContact= Search-EXRContacts -MailboxName user@domain -emailaddressKQL 'myaddress@domain.com' Set-EXRContactPhoto -Id $ExistingContact.id -FileName c:\photos\mycont.jpgExport an existing Contact to a VCard$ExistingContact = Search-EXRContacts -MailboxName user@domain -emailaddressKQL 'myaddress@domain.com' Export-EXRContactToVcard -Id $ExistingContact.id -SaveAsFileName c:\photos\mycont.vcfDeleting a Contact $ExistingContact = Search-EXRContacts -MailboxName user@domain -emailaddressKQL 'myaddress@domain.com' Invoke-DeleteEXRContactd -Id $ExistingContact.id  Enumerating all Contacts in a Contacts FolderThe Default Contacts folder in a MailboxGet-EXRContacts -MailboxName user@domain Other Contact Folders Get-EXRContacts -MailboxName user@domain -ContactsFolderName FolderNameDirectory (AD) ContactsEnumerating Directory ContactsGet-EXRDirectoryContacts Export a Directory Contact to Vcard$dirContact = Get-EXRDirectoryContacts | Where-Object {$_.mail -eq 'glenscales@yahoo.com'} Export-EXRDirectoryContactToVcard -Id $ExistingContact.id -SaveAsFileName c:\photos\mycont.vcfSome things that are still missing in the Graph API is the ability to manage private distribution lists which will probably come along at a later date. The source for all the new cmldets are available on GitHub https://github.com/gscales/Exch-Rest/tree/master/functions/contacts[...]



EWS-FAI Module for browsing and updating Exchange Folder Associated Items from PowerShell

2018-03-12T15:57:15.983+11:00

Folder Associated Items are hidden Items in Exchange Mailbox folders that are commonly used to hold configuration settings for various Mailbox Clients and services that use Mailboxes. Some common examples of FAI's are Categories,OWA Signatures and WorkHours there is some more detailed documentation in the https://msdn.microsoft.com/en-us/library/cc463899(v=exchg.80).aspx protocol document. In EWS these configuration items can be accessed via the UserConfiguration operation https://msdn.microsoft.com/en-us/library/office/dd899439(v=exchg.150).aspx which will give you access to either the RoamingDictionary, XMLStream or BinaryStream data properties that holds the configuration depending on what type of FAI data is being stored.I've written a number of scripts over the years that target particular FAI's (eg this one that reads the workhours http://gsexdev.blogspot.com.au/2015/11/finding-timezone-being-used-in-mailbox.html is a good example ) but I didn't have a generic script that could allow you to browse and read the data from any FAI in a Mailbox which would be useful when you are trying to peer into FAI's when debugging or reporting on different clients and services that use these FAI's.So what I've done for this post in publish a really basic Powershell Module to the PowerShell Gallery https://www.powershellgallery.com/packages/EWS-FAI that can do this. The script requires that you have the EWS Managed API installed and then it has two Cmdlets. The source for the module can be found on GitHub here https://github.com/gscales/Powershell-Scripts/tree/master/EWS-FAI/ModuleInvoke-ListFAIItemsThe cmdlet will browse and display a list of any configuration FAI Items in a Folder eg to show the Items in the Non_IPM_SubTree useInvoke-ListFAIItems -MailboxName mailbox@domain.com -Folder Root  it will produce an output such asOther folders such as the Inbox and Calendar contain some of the more useful FAI's egA quick rundown on theseAvailiablityOptions is a newieCalendar Contains the calendar processing information more of intrest when looking at a room mailboxCategoryList Is the Master Cateogry List of a Mailbox (XML)WorkHours Is the workhours setting for a Mailbox (XML)Get-FAIItemIf you see an FAI that you want to view the contents of for example the OWA.UserOptions this the cmdlet you can use to do thisGet-FAIItem -MailboxName mailbox@domain.com -Folder Root -ConfigItemName OWA.UserOptionsegBecause this FAI is a Roaming Directory this is what is returned to the pipeline.If you have an FAI the contains XML like the Category list the cmdlet will return XML back to you which you may or may not be able to work with depending on your skill level in PowerShell. But if you just want to look at the Content in plain text at the cmdlet line you can do the followingGet-FAIItem -MailboxName mailbox@domain.com -Folder Calendar -ConfigItemName CategoryList | Select-Object InnerXML | FLThe other optional parameter for this cmdlet is the -ReturnConfigObject switch which will return the actual UserConfiguration Typed object from the EWS Managed API which is useful if you want to update the FAI in question or your dealing with the BinaryStream which this module doesn't handle. Eg you can use the following script to turn off the FocusedInbox in OWA for a user$OwaOptions = Get-FAIItem -MailboxName user@domain.com -Folder Root -ConfigItemName OWA.UserOptions -ReturnConfigObjectif($OwaOptions.Dictionary.ContainsKey("IsFocusedInboxEnabled")){ $OwaOptions.Dictionary["IsFocusedInboxEnabled"] = $false $OwaOptions.Update()}One last one because it was the topic of a recent conversation is if you want to look to see the user configuration status for the  Focused Inbox in Outlook you can use the following to read the FAI that stores this information.Get-FAIItem -MailboxName mailbox@domain.com -Folder Inbox -ConfigItemName AccountPrefs eg this will return something like[...]



Looking into the Microsoft Team's TeamChat folder in an Office365 Mailbox using EWS

2018-02-21T18:03:25.084+11:00

If you looked at the folder structure in an Office365 Mailbox (or older Exchange Mailbox) using a MAPI editor so you could see all the Non_IPM_Subtree and hidden folders around 5 years ago it was a relatively simple picture. Today with the rapid pace of the change in Office365 its a little bit of minefield on new folders and hidden data that is stored and used by various applications in your Mailbox. A good case in point is the Files Hidden folder which Tony explains about in https://www.petri.com/mysterious-files-folder . Microsoft Teams is the new kid on the block in terms of collaboration applications that integrate into Mailboxes and other Office365 workloads. As you chat using the Microsoft Teams client as part of it compliance/discoverability process associated with Microsoft Teams a cloud-based process creates conversation items in a Hidden folder in your Office365 Mailbox called TeamChat (this is a Subfolder of the Conversation history). Because its a hidden folder users won't be able to see the content but the data stored is searchable (at the time of writing this there is very little official documentation that I can find Tony's post https://www.petri.com/teams-compliance-story and a few other forum posts give the best guide to what this is and how it works).So because this is a hidden folder using the new Graph API won't work (although you can actually get to the Items using the Graph API by searching) so using EWS is the best approach for now as it gives the most flexibility if you want to start playing around with this data programmatically.Binding to the folder in EWSYou could use a few different ways to get the TeamChat folder the approach I've used is to make use of the Extended Property TeamChatFolderEntryId which is set on the Root Folder of a Mailbox. This contains the PR_EntryId of the Folder in question so once you convert this to an EWSId using the CovertId operation in EWS you can then bind directly to the folder. eg here's what the code looks like$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)   $TeamChatFolderEntryId = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([System.Guid]::Parse("{E49D64DA-9F3B-41AC-9684-C6E01F30CDFA}"), "TeamChatFolderEntryId", [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);$psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $psPropset.Add($TeamChatFolderEntryId)$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid,$psPropset)$FolderIdVal = $nullif ($RootFolder.TryGetProperty($TeamChatFolderEntryId,[ref]$FolderIdVal)) {   $TeamChatFolderId= new-object Microsoft.Exchange.WebServices.Data.FolderId((ConvertId -HexId ([System.BitConverter]::ToString($FolderIdVal).Replace("-","")) -service $service))   $TeamChatFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$TeamChatFolderId);  }}Once you have access to the Folder you can start pulling basic folder statistics like the Number of Items, Sizes, AttachmentCounts etc (or more interestingly things you won't be able to do using Get-MailboxFolderstatitistics). But the more interesting thing to do is to look at the data stored on the conversation items, because these aren't your normal email Messages extended properties are used to hold the different data from Teams/Skype (also the normal Attachment and recipients collections of a message are also used). There are a few properties in use (which generally aren't documented either so if your interested I would suggest taking a look yourself with a MAPI editor at a few items). But the one that is of most interest to me anyway is the SkypeMessagePropertyBag which contains a lot the Metadata from the chat message. This is a string property that contain JSON so accessing and d[...]



Searching Mailbox folders using the REST API In Powershell on Office365 and Exchange 2016

2018-02-02T16:03:43.567+11:00

PrefaceSearching Mailboxes is something I've written a fair bit about in the past but in this article I'm going to cover how searching has been surfaced in the new REST API on Office365 and Exchange 2016.  The first place to go when considering searching in Office365 is the Security and Compliance center https://support.office.com/en-us/article/run-a-content-search-in-the-office-365-security-compliance-center-61852fd9-fe8a-4880-a339-cb19ed3bff4a it offers the most feature rich and realistic search experience that is difficult to replicate with client facing Mailbox API's (eg things like RBAC's delegated access rights, litigation holds etc). Given the amount of data that can be stored in Mailboxes now its important to have a realistic expectation of the time it will take and difficulty of searching 100,000's items in multiple folders or millions of items in an Archive is important (at the time of writing Archives aren't accessible using the REST API).Searching MailboxesWithin an Office365 Mailbox there are number of different methods for performing a Search using the REST API for particular items within a particular Mailbox folder or across all folders in a mailbox. Depending on the properties you want to search on and the amount of data you expect to return in your search you should select the most appropriate method to use.Using filters (or Restrictions)Restrictions are the standard way in which searches are normally carried out in Outlook and Exchange, restrictions are property based searches on one or more properties and may involve a number of operators such as equals, greatorthan, lessthan, contains (for substrings) or startswith. In the REST API restriction are implemented via the $filter Query Parameter. Because the raw content is queried this type of search can take longer to perform if the underlying folder has a larger number of items or the restriction being used is very complicated. A common issue that can occur using filters is the Query will timeout or will be throttled because of the overall load it produces on the server. Some more background on restrictions can be found https://technet.microsoft.com/en-us/library/bb267022(v=exchg.80).aspxUsing KQL (or Exchange Search)Exchange Search is the full text indexing feature of Exchange which indexes contents automatically (asynchronously) as email arrives in a Mailbox.This type of Search utilizes the KQL (Keyword Query Logic) that is also used with in Share-point for query processing. This is the faster and more efficient method of searching a Mailbox because it utilizes Full Text Indexes rather then needing to query the raw content and should be the preferred starting point for search. However there are some limitations on the properties that can be searched using this method and also on the amount of results that will be returned by a query. In the REST API KQL queries are performed using the $search Query Parameter.Property restrictions : As Exchange only indexes certain properties for performance reason only certain properties can be searched using KQL a full list of the indexed properties the can be used can be found https://support.office.com/en-us/article/keyword-queries-and-search-conditions-for-content-search-c4639c2e-7223-4302-8e0d-b6e10f1c3be3#emailpropertiesMaximum Result Sets: Exchange limits the maximum result set of Exchange Search queries to 250 Items in REST and EWS. with OnPrem Servers this value is adjustable via the MaxHitsForFullTextIndexSearches property https://support.microsoft.com/en-us/help/3093866/the-number-of-search-results-can-t-be-more-than-250-when-you-search-em however in Exchange OnLine (Office365) you can't adjust that value and need to work under the 250 item ceiling.Using SearchFoldersSearch Folders are Special Mailbox folders that contain no items but return linked Items based on a predefined search criteria (usually the same as you would use in Filters). Because these are constantl[...]



A walk-though using the Graph API Mailbox reports in Powershell

2018-01-19T16:31:52.626+11:00

Quite recently the Reporting side of the Graph API has moved in GA from beta, there are quite a number of reports that can be run across various Office365 surfaces but in this post I'm going to focus on the Mailbox related ones.Accessing Office365 Reports using Powershell is nothing new and has been available in the previous reporting endpoint https://msdn.microsoft.com/en-us/library/office/jj984326.aspx however from the end of January many of these cmdlets are now being depreciated in favour of the Graph API https://msdn.microsoft.com/en-us/library/office/dn387059.aspx . Prerequisites In comparison to using the Remote PowerShell cmdlets where only the correct Office365 Admin permissions where needed, to use the new Graph API reports endpoint you need to use OAuth for authentication so this requires an Application Registration https://developer.microsoft.com/en-us/graph/docs/concepts/auth_overview  that is then given the correct oAuth Grants to use the Reports EndPoint. Only one particular grant is need for this egThis is a big advantage over the previous Web Service along with the benefits of using Token based authentication and different App usage scenarios it limits access to just what is needed to read reports which help limit the security risks associated.Accessing the Reporting EndpointTo access and Run the reports you will need code that first Authenticates and generates an oAuth Token based on your App registration. My Exch-Rest module can be used for this (Connect-EXRMailbox will imitate the token Authentication) or there are other scripts people have posted that can also do this https://gallery.technet.microsoft.com/Get-Office365-usage-f955ade4 .Inputs and OutputsCompared to the  Remote PowerShell cmdlets the richness of Input parameters for the reports at GA is limited (even when compared to the beta which was more a little rich). For most of the Mailbox Reports the only input parameter is the Period best explained in the documentation"Specifies the length of time over which the report is aggregated. The supported values for {period_value} are: D7, D30, D90, and D180. These values follow the format Dn where n represents the number of days over which the report is aggregated" ref https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/reportroot_getmailboxusagedetailSo if your trying to feature match your current scripts against the new Graph API you may need to look at restructuring or rethinking your process a little, at the end of the day the data is same but you may need to post process it more at the client side.On the Output side a CSV is generated by the Graph API and returned to the user, currently because the endpoint doesn't yet support the Filter Query parameter if you want to perform any filtering you will need to do it post process once the CSV is downloaded. (I would expect that in future updates the other QueryStrings will be supported which will improve the flexibility for those working with very larger result sets in Larger tenants.The Actual Reports Given the refresh time of the Graph API it mostly likely this list is already out of date by the time you read this. All the screenshots are from the reporting Cmdlets in lastest version of my Exch-Rest Module which you can get from the PowerShell gallery https://www.powershellgallery.com/packages/Exch-Rest  to use the cmdlets you need to first authenticate using Connect-ExrMailbox with an app registration that has been granted the "Read Usage Report" permission.GetMailboxUsageDetails https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/reportroot_getmailboxusagedetailThis report returns mailbox usage information or in plane English how big your Mailbox is and what the Quotas are. egThe Remote PowerShell cmdlet Get-MailboxUsageDetailReport returned the same information with a few extra fields but these fields are retrievable [...]



Major update to my Exch-Rest Powershell Module for accessing Office365 and Exchange 2016 Mailboxes via REST

2018-01-03T16:55:26.471+11:00

For about a year I've being working on a PowerShell Module for accessing the new REST API for Office365 (the Graph API) and Exchange 2016. I've been experimenting and listening to the various feedback I've been getting and finally have an update to share that addresses a lot of the useability issues (okay it was just too developer orientated).

Application registrations

Still probably the biggest stumbling block is not having an application registration, I now have a menu that allows to you use various default registrations for testing and also to save a default registration that you create. This means once you have your own registration setup you can save the ClientId so it will be used as the default when you next use the module.

Aliasing

A failure in proper planning when I initially created the module meant I didn't use a specific alias for the cmdlets in the module which meant it can cause a lot of conflicts if you have other modules loaded. With the new version all cmldets have a -EXR moniker.

Token Caching

With previous versions of the module you basically would authenticate and create an access token and store that in a local variable which you then had to pass into each of the cmdlets using the -AccessToken parameter along with the MailboxName. This meant a lot of typing and really broke the useability flow without really providing any security benefits. With the new module while all these old behaviours are still valid there is now a Connect-EXRMailbox cmdlet which is the new entry point cmdlet which will store the token and the name of the mailbox associated with the Token in a script variable (encrypted of course) but accessible by the module. This means you can run most of the cmdlets without specifying a Mailbox or Access Token if you just want to return details about the current mailbox that has been authenticated. Also when it comes to using Directory or Reporting cmdlets it eliminates the need for MailboxName which used mandatory parameter on all cmdlets. 

New Getting Started Guide 

With this type of project documentation is the hardest thing as its the least interesting and more time consuming things to get correct. I've written a new getting Started Guide for people that haven't used the module before. The old readme guide is still valid so if your looking to use App Tokens this going to be useful

New Cmdlets

I have a lot of new cmldets most aren't documented in anyway but I hope to put these more into Context in the new year on the blog and on GitHub. Things like accessing the Reporting API's is interesting which I've covered briefly in the new Getting Started guide.

The new module Exch-Rest is available from the PowerShell Gallery here or the source code which will contains all the latest code is available on GitHub here.

 Feedback and Contributions

As always I welcome any feedback or contributors who want to improve the module




Doing recursive CSV contact exports from Mailboxes and Public Folders

2017-12-14T17:07:33.625+11:00

One of the scripts that I posted that seems to have a steady stream of input is the EWSContacts Module I put up some time ago. Thanks to Friedrich Weinmann who did some recent cleanup of the module on GitHub it is now looking a lot neater.

After a recent question from somebody I've made some more changes to the Export-EXCContactFolder function to allow you to if your exporting a Public Folder or a mailbox's Contacts Folder to recurse any subfolders of that folder you passed in and export those contacts also. When this option is selected a field is added to the CSV to tell you which MailboxFolder (or PublicFolder) the contact was exported from.

To use this new feature when exporting contacts from a Public folder just use the recurse switch eg

Export-EXCContactFolder -PublicFolderPath "\Office Contacts" -Recurse -MailboxName gscales@datarumble.com -FileName c:\temp\alc2.csv

Another parameter I've added is the -RecurseMailbox which will instead of starting at the default Contacts Folder in a Mailbox it will now start at the Mailbox root, iterate ever folder in the Mailbox and do a CSV export of any contacts in any folders in the Mailbox as long as those folder aren't hidden (a hidden folder generally indicates this is an Outlook System Folder so not something you want to process). Eg

Export-EXCContactFolder -RecurseMailbox -MailboxName gscales@datarumble.com -FileName c:\temp\alc2.csv
One last fix was to switch to using UTF8 encoding in the CSV so if your exporting contacts with non Ascii character it will now support this instead of showing a bunch of ???

The updated code is available on GitHub and I've also now published the Module here in the PowerShell Gallery To install the module from the gallery just use

Install-Module ExchangeContacts




Using OWA's Pin email feature using EWS in Office365 and Exchange 2016

2017-11-29T19:49:26.840+11:00

Pinning email is a new feature that is available in OWA(or Outlook on the Web) on Office365 and Exchange 2016 and a much requested feature in Outlook https://outlook.uservoice.com/forums/322590-outlook-2016-for-windows/suggestions/12963459-pin-or-stick-important-emails-at-the-top-of-your-IWhat happens when you pin an Email in OWA is it sets two MAPI properties on the backend when pinned the value will look like the followingthe value 1/9/4500 is significant and is used when an Item in Pinned in the UI, When the Item is Unpinned in the UI 0x0F01 reverts back the current time and 0x0F02 is removed from the item. So in EWS if you want to display all the Pinned email you can use a SearchFilter to filter the Item based on the value of this property eg $PR_RenewTime2 = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0xF02,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::SystemTime);  $SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsGreaterThan($PR_RenewTime2, [DateTime]::Parse("4500-9-1"))I've create a PowerShell EWS Module to enumerate the Pin Item in a folder here https://github.com/gscales/Powershell-Scripts/blob/master/PinEmail.ps1To show Pinned Email in the Inbox you can use Get-PinnedEmail -MailboxName gscales@datarumble.com -FolderPath \InboxTo Unpin Email you can use the Set-UnPinEmail function to pass in a EWS Managed API Item type eg Set-UnPinEmail -Item $itemOne real life example where this came in handy was I recently managed to pin over 800 emails in my mailbox through inadvertently enabling a InboxRule using the Pin Email action that procesed every incoming message. When I switched the rule off recently which i didn't think much off a the time I could then nolonger see any new messages arriving in OWA because they where appearing under the pinned email (800 deep in my mailbox no matter how I sorted the email). It didn't register what the problem was a first (as a long term user i just ignored the pin icon)and thought it maybe an OWA bug that would be fixed in the next service update and it embarrassingly took me a few weeks to realise what the actual problem was. Unpinning email one at a time would have taken me a very long time hence this script.So to unpin all email in the Inbox you can useGet-PinnedEmail -MailboxName gscales@datarumble.com -FolderPath \Inbox | foreach-object{Set-UnPinEmail -Item $_}To fill out the function in this module there is also a Set-PinEmail function and an example function that uses this which will Pin the last received email in the Inbox eg Invoke-PinLastEmail -MailboxName gscales@datarumble.com -FolderPath \InboxAll the code for this post can be found on GitHub here https://github.com/gscales/Powershell-Scripts/blob/master/PinEmail.ps1[...]



Simple Mail Gui's for the REST API on Office365 and Exchange 2016

2017-11-02T16:55:45.844+11:00

As I've been adding new cmdlets to my Exch-REST PowerShell module I've been knocking up against some of the limitations and frustrations of working within a console environment. One of them is if say I find some Messages within a Mailbox which needs further investigation for whatever reason, It good to have an easy way of opening up that message to take a look at the content that isn't normally easy to view in the cmdline like the html body of a message and maybe I want to download any attachments or MessageHeaders without needing to open Outlook or OWA. A number of years ago I created a simple EWS mail client that just acted as a simple Email client using EWS so I decided to port this to the REST API and include it in the Exch-Rest Module. I also broke out two of the winforms from this simple client to enable just reading a particular Message you may have found using any of the other cmldets as well as a simple Form to Send a New Message with or without an Attachment.So with Version 2.7 of the Exch-REST Module you can now use theStart-EXRMailClient cmdlet which will start the small mail client which will use the underlying Exch-REST Module cmldets to open and browse Mailbox Mail folders, Read Items from a Folder you select in the TreeView, Show Internet Message Headers or Download attachments from messages in the datagrid egGetting Messages from the InboxShowing the content of a Messageor show the Message HeadersYou can either start the Mailbox client using Start-EXRMailClient cmdlet with no parameters or pass in a Mailbox and AccessToken you maybe working with and it will automatically enumerate the Folders from that Mailbox using the token passed in.To use the Read Message Form on a message you have found in the cmdline through using another cmdlet eg to open the last message in the Inbox you could use$Items = Get-WellKnownFolderItems -MailboxName gscales@datarumble.com -AccessToken $AccessToken -WellKnownFolder Inbox -TopOnly:$true -Top 1Invoke-EXRReadEmail -ItemRESTURI $Items[0].ItemRESTURI -AccessToken $AccessToken -MailboxName gscales@datarumble.comTo Start the New Message form just useInvoke-EXRNewMessagesForm -MailboxName gscales@datarumble.com -AccessToken $AccessToken[...]



Export Contacts from a Mailbox Contacts Folder or Public Folder to a CSV file using EWS and REST

2017-10-17T20:53:05.696+11:00

As I had a few questions about exporting contacts to CSV from both Mailbox and Public folders I've added some new functions to the my EWS contacts module to make this easier.  I've added to new cmdlets the first is

Export-ContactsFolderToCSV

This will export a contacts folder to CSV's either the default Contacts Folder in a Mailbox or a secondary Contacts folder if you enter in the FolderPath eg to export the Default contacts Folder use

Export-ContactsFolderToCSV - MailboxName user@domain.com -FileName c:\exports\contacts.csv

To export a Secondary Contacts Folder use

Export-ContactsFolderToCSV - MailboxName user@domain.com -FileName c:\exports\contacts.csv -Folder \Contacts\SecondContactsFolder

Export-PublicFolderContactsFolderToCSV

This will export a Public Contacts Folder to a CSV file to use this use

Export-PublicFolderContactsFolderToCSV -MailboxName mailbox@domain.com -FileName c:\exports\PublicFolderexport.csv -PublicFolderPath \folder\folder2\contacts

The EWS Contacts Module is available on GitHub here https://github.com/gscales/Powershell-Scripts/blob/master/EWSContacts/EWSContactFunctions.ps1

I've also added some code to my Exch-REST module to allow export of a Contacts Folder using the new REST API on Office365 and Exchange 2016. To use this you need version 2.4 of the module from the PowershellGallery https://www.powershellgallery.com/packages/Exch-Rest then use

Export-ContactFolderToCSV -MailboxName tmpcontact@domain.com -AccessToken $AccessToken -FileName c:\exports\filename.csv







Showing all your Room Mailboxes in Office365 using the Graph REST API

2017-10-04T17:51:10.134+11:00

One of the recurring questions you see asked in Forums around EWS is the ability to see all the Room Mailboxes in Exchange. This is pretty reasonable request that hasn't really had an easy answer in the past there are RoomLists but these required setup and ongoing maintenance and coordination  which can be troublesome. If you where using OnPrem exchange then instead of using EWS you could just use LDAP to lookup Active Directory directly (as well all know AD is the directory service for Exchange) eg back in 2007 I created this http://gsexdev.blogspot.com.au/2007/04/webservice-to-find-room-and-equipment.html.With Office365 you don't have LDAP access to the directory and the Graph API while its good doesn't offer access to the particular property on a User or Directory Object that would allow you to tell if that object has an associated Room (or group or shared mailbox). The good news however is the Graph API  now gives you the ability to pull all the Room Mailbox using findrooms operation https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/user_findroomsI've added support for this to my Exch-Rest Module in the Powershell gallery https://www.powershellgallery.com/packages/Exch-Rest  so you can now get this with a script like the following using the Beta namespace$Token = Get-AccessToken -MailboxName mailbox@domain.com -ClientId 5471030d-f311-4c5d-91ef-74ca885463a7 -redirectUrl urn:ietf:wg:oauth:2.0:oob -ResourceURL graph.microsoft.com -beta Find-Rooms -Mailbox mailbox@domain.com -AccessToken $Token and it returns a simple list of your Room mailboxes likeYou could also pipe the results into another script to find the usages of those room mailboxes for the next day. To do this I use the Get-CalendarView cmdlet which makes a request for the next 24 hours of appointments using a CalendarView as documented in https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_list_calendarview (for this to work you need to have rights on all the Rooms you want to report on else you will get a 'Service Unavailable' error)$MailboxName = "gscales@datarumble.com"$Token = Get-AccessToken -MailboxName $MailboxName -ClientId 5471030d-f311-4c5d-91ef-74ca885463a7 -redirectUrl urn:ietf:wg:oauth:2.0:oob -ResourceURL graph.microsoft.com -beta $rptCollection = @()Find-Rooms -Mailbox $MailboxName -AccessToken $Token | foreach-object{ $RoomAddress = $_.address Get-CalendarView -MailboxName $_.address -StartTime (Get-Date) -EndTime (Get-Date).AddDays(1) -AccessToken $Token | foreach-object{ $rptObj = "" | Select Room,Organizer,Subject,Start,End $rptObj.Room = $RoomAddress $rptObj.Organizer = $_.organizer.emailAddress.name $rptObj.Subject = $_.subject $rptObj.Start = [DateTime]::Parse($_.start.datetime).ToString("yyyy-MM-ddTHH:mm:ss") $rptObj.End = [DateTime]::Parse($_.end.datetime).ToString("yyyy-MM-ddTHH:mm:ss") $rptCollection += $rptObj }}$rptCollectionYou can then turn the collection into a CSV or HTML file as you likeThis full sample with HTML output and the module source code can be found on GitHub here https://github.com/gscales/Exch-Rest (sample is in samples)[...]



Using the Office365/Exchange 2016 REST API Calendaring

2017-09-12T18:15:31.401+10:00

When it comes to Messaging API's there no more complex thing then calendaring, not only because most vendors implement things a little differently but Exchange also has a little legacy feature drag because of its length of time in the market place and the difficulties in changing the technology and human interaction with it. The new REST API offers yet another window into calendaring on Office 365 and Exchange 2016 with a major security benefit over its predecessor which is the ability to be able to scope your application access so it can only access the Calendar folders in a Mailbox where previously apps may have needed to have Full Rights or impersonation rights on a Calendar. Also the new REST API allows you to interact with Group Calendars (or Teams Calendar) so leveraging the new REST API to value add to the adoption of these new features can be a worth your while.To Support Calendaring I've added 2 new cmdlets to the Exch-Rest module to handle creating Appointments and Meeting and a few other supporting cmdlets to create the data structures necessary to handle each of the data types. I have a full documentation page with examples on GitHub here https://github.com/gscales/Exch-Rest/blob/master/Samples/CalendaringExamples.mdCalendaring TypesAs I mentioned in my opening there is no more complex a thing then calendaring so lets look briefly at the converge I've added so far in the ModuleCreating a Single Appointment in the default CalendarFairly basic thing to do you use the New-CalendarEventRest cmdlet to specify all the properties you want to set in this New AppointmentNew-CalendarEventREST -MailboxName mailbox@datarumble.com -AcessToken $AccessToken -Start ([DateTime]::Parse("2017-07-05 13:00")) -End ([DateTime]::Parse("2017-07-05 14:00")) -Subject "Name of Event"Creating a Single Appointment in the secondary CalendarThe new REST API allows you to enumerate all the calendars in a Mailbox and returns them as a flat list structure (rather then a parent/child like Mailboxes). To cater for creating appointments on Secondary Calendar's (eg any calendar other then the default) I included a -CalendarName parameter which first finds the secondary calendar using a filter based on the DisplayName and then allows you to create the appointment like in the first example egNew-CalendarEventREST -MailboxName mailbox@datarumble.com -AcessToken $AccessToken -Start ([DateTime]::Parse("2017-07-05 13:00")) -End ([DateTime]::Parse("2017-07-05 14:00")) -Subject "Name of Event" -CalendarName 'Secondary calendar'Creating a Single Appointment on a Group CalendarTo create an Event on a Group (or Teams) Calendar the user your using to access the REST API must be a member of that group in question and have the necessary rights on that Calendar. To cater for the necessary changes to the REST Uri you need to post to for groups which involves first finding the GroupId of the Group you want to access, I've added a -Group switch and -GroupName parameter to the cmdlets. The cmdlets then will use a lookup of the group based on its displayname to find the GroupId first and then POST to the Group calendar. (The organizer of the appointment you create on the Group Calendar becomes the Mailbox your posting as). Eg#Creates a new all event for the 5th of July from 13:00-14:00 on the a group calendar called 'Powershell Module'New-CalendarEventREST -MailboxName mailbox@datarumble.com -AcessToken $AccessToken -Start ([DateTime]::Parse("2017-07-05 13:00")) -End ([DateTime]::Parse("2017-07-05 14:00")) -Subject "Name of Event" -group -groupname 'Powershell Module'Creating a Recurring AppointmentAppointment or Meeting Recurrence is probably the hardest thing when it comes to Calendaring for developers and admin to understand because the[...]



Reporting on the Public Folder favorites in a Mailbox using EWS and Powershell

2017-08-23T19:07:27.248+10:00

Outlook and OWA allow you to create "Favorites" shortcuts to Public folders (and other folders for that matter) to make accessing them a faster experience.For those of us keeping pace with grinding Public Folders into dust (personally no longer a fan) and replacing them with Groups, it maybe useful to report on which Public Folders people have Favorited in their mailboxes for a metric and impact point of view. This information should then come in useful if your planing on migrating them (or just for a laugh). Because Public folder hierarchies are relatively complex having the path to the Public folder rather then just the name is generally a lot more useful. So in the script in this blog post we will look at producing a report of the Public Folder favorites and the Path of the Public Folders those shortcuts refer to eg it will produce a report something like the following for each mailbox you where to run it against.Like other mailbox shortcuts these favorites are FAI (Folder associated items) stored in the Common Views Folder in the Non IPM Subtree folder of a Mailbox. Other names for these items are wunderbar or navigation shortcuts and are documented in https://msdn.microsoft.com/en-us/library/ee157359(v=exchg.80).aspxEWS allows relatively easy access to FAI items in a Mailbox folder by using an Associated Item traversal in the FindItems operation. eg$ivItemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated To restrict the query to just returning those items that are public folder shortcuts you need to put a restriction on the  PidTagWlinkFlags property.The actual properties on the FAI Items must be accessed using extended properties in EWS which are documented in the Exchange protocol document linked above. To work out the path to folder you need to get the PidTagWlinkEntryId property which returns the EntryId of the PublicFolder that the shortcut points to which you then need to convert to an EWSId to access the Public Folder in question. However it is not quite as straight forward as this because the EntryId that is returned by this property isn't convertible with EWS ConvertId operation because of one of the flag properties used. So some transposition of the EntryId is required, because the EntryId format is documented here https://msdn.microsoft.com/en-us/library/ee217297(v=exchg.80).aspx transposing out the incompatible flags so the EntryId can then be used in EWS's convertId operation isn't that hard. eg$TransposedId = "000000001A447390AA6611CD9BC800AA002FC45A0300" + $Id.Substring(44)(1A.44.73.90.AA.66.11.CD.9B.C8.00.AA.00.2F.C4.5A. is the provider Id for Public folder and 0300 is folderType for PublicFolder)Once you have the EWSId of the Public Folder you can then access the PR_Folder_Path property of the folder which should return the full path (with Unicode separators) to the Public Folder in question which you can then add to a report. From a permissions perspective this script needs to be able to access the CommonViews folder in a Mailbox and the Public Folder that the shortcut refers to which maybe a complex thing in some circumstances. As an alternative to binding to the Public Folder using EWS to get the Public folder Path in question you could also use Remote Powershell (Get-PublicFolder) as a alternative if permissions cause an issue.I've put a copy of this script on Git hub https://github.com/gscales/Powershell-Scripts/blob/master/GetPfShortCuts.ps1To run this script use Get-PublicFolderShortCuts -MailboxName gscales@datarumble.com[...]



Generic Folder Picker for Mailboxes for use in REST based Powershell Office365 / MSExchange Scripts

2017-08-11T11:54:31.928+10:00

This is a continuance of my Office365/Exchange 2016 Rest series, in this post I'll be showing how some of the new GUI elements in the Exch-Rest module can help improve the speed and usability of any scripts where you need to browse Mailbox folders. What this modification to the Module does is allows you to enumerate all the Mail Folders in a Mailbox using the REST API and then present a simple folder tree that then allows you to browse through the folder in a Mailbox you might be looking for and when you double click that folder it will then return that as an object that can be piped into further operations. eg the new cmdlet works likeInvoke-MailFolderPicker -MailboxName gscales@datarumble.com -AccessToken $AccessTokenand visually this is what it looks likeI have one extra feature I've added into the module that allows you to return the same folder tree as above with the folder sizes in MB. To do this you need to make sure of the Extended Property (PR_MESSAGE_SIZE_EXTENDED Mapi property). To use this run the Invoke-MailFolderPicker cmdlet with the -ShowFolderSize switch egInvoke-MailFolderPicker -MailboxName gscales@datarumble.com -AccessToken $AccessToken -ShowFolderSize will return something likeHow it works The Invoke-MailFolderPicker cmdlet is an amalgam of other functions in the Exch-Rest module (this is actually the main reason I've been building this module in the first place while the individual functions within the module are relatively easy to reproduce you need a large library of these small functions to build things that are really interesting and useful). So to build a Tree we first need a root so getting the Root Folder of the Mailbox is done using$rootFolder = Get-RootMailFolder -AccessToken $AccessToken -MailboxName $MailboxNameThe important part here is to know the Id of the root folder so when you look at the parent FolderId properties of any child folder you can construct a Tree of folders from that.To cater for Foldersizes if the ShowFolderSize switch  is used you need to use an Extended property because there is no strongly typed property for FolderSize that is returned by the REST API (this was the same in EWS as well). To do this the following code snippet is used    $PropList = @()    $FolderSizeProp = Get-TaggedProperty -Id "0x0E08" -DataType Long    $PropList += $FolderSizeProp    $Folders = Get-AllMailFolders -MailboxName $MailboxName -AccessToken $AccessToken -PropList $PropListThis builds out the correct expansion string for these extended properties as well as catering for the differences between the graph and Outlook endpoints. The Get-AllMailFolder cmdlets just gets all the child folders of the Mailbox and returns them as a collection. Finally the  Invoke-FolderPicker -MailboxName $MailboxName -Folders $Folders -rootFolder $rootFolder -pickerType mail -ShowFolderSizeUsing the Windows form and the Treeview control to build a visual representation of the Mailbox folder tree and return it to initiator.Practical useI've come up with a practical sample of this located https://github.com/gscales/Exch-Rest/blob/master/Samples/showLast10.ps1 that will once you double click the target folder will return the last 10 items in a folder to the PowerShell window. This is a simple 4 line script including the code to get the Token$MailboxName = "gscales@datarumble.com"$AccessToken = Get-AccessToken -MailboxName $MailboxName -ClientId 5471030d-f311-4c5d-91ef-74ca885463a7 -redirectUrl urn:ietf:wg:oauth:2.0:oob -ResourceURL graph.microsoft.com$FolderSelected = Invoke-MailFolderPicker -MailboxName $MailboxName -AccessToken $AccessToken -ShowFolderSi[...]



Using the Office365/Exchange 2016 REST API for working with Mailbox and OneDrive files/attachments

2017-07-19T20:15:49.073+10:00

In my last post I demonstrated how to rewrite a simple download process script from using EWS to using the new REST API in Office365. This was an example of an Automation process that I first used in the early 2000's as back then email offered a ubiquity for a simple data transfer that even today is hard to do in some enterprises which is why that post has been so popular over the years.In this post I'm going to show you how you can make use of other Office365 endpoints available in the Graph API to basically take this old process and start improving on it. The particular Endpoint I'll be focusing on in this post is OneDrive https://dev.onedrive.com/ (or One Drive for business). I'll also be using my Exch-Rest Module and taking advantage of all the existing code I've written for the interacting with  Exchange Online to interact with the OneDrive endpoint. And that really is the one great thing about the new Graph Endpoint is that all I've needed to do to add OneDrive functionally to my module is to create some new functions to deal with the specific addressing differences between Mail and One Drive while the underlying Auth, Get and Post function are the same (so speed and agility in marketing fluff and less hours recoding in real speak).Basics of Interacting with One DriveAuthentication : To use One Drive from the Exch-Rest Module the application registration you have been using for your Mail scripts needs to be granted the OneDrive Permission Grants in the Azure portal https://dev.onedrive.com/auth/graph_oauth.htm. Once the grants have been added they will be then returned when AccessToken is requested, so basically you can use the same AccessToken for accessing Email and OneDrive without the need to authenticate again.Paths and Drives: Each user has a default OneDrive drive which you can access using the /drive/root path . If you know the Id of the file you want to access then you can use the following Path drive/items/{item-id} to access it otherwise if you know the relative path (eg folder path/filename) then this can be used like /drive/root:/path/to/file to access the file. (this is a pretty basic explanation but the documentation cover this in more depth https://dev.onedrive.com/ ) This will make more sense when you look at an example so lets start Modern Attachments aka Reference AttachmentsModern Attachments is a new feature introduced into Exchange,Office365 and Outlook 2016 that was a kind of inbuilt OneDrive and Exchange integration feature. In EWS and REST these type of attachments are called reference attachments . Within the REST API currently Reference attachments are supported in the v2.0 Outlook endpoint and the Beta endpoint in the current Graph API. I've added support for sending reference attachments in Exch-Rest (v1.9) so an example of sending a reference attachment (eg a one drive file) using the Graph Beta Endpoint using the module would look likeImport-Module Exch-Rest -Force$MailboxName = "gscales@datarumble.com"$OneDriveFile = "/test/test2/fileName.zip"$DownloadDirectory = "c:\temp"##Get the Access Token$AccessToken =  Get-AccessToken -MailboxName $MailboxName  -ClientId 5471030d-f311-4c5d-91ef-74ca885463a7 -redirectUrl "urn:ietf:wg:oauth:2.0:oob" -ResourceURL graph.microsoft.com -Beta ##Get OneDrive DownloadURI$OneDriveAttachmentToSend = Get-OneDriveItemFromPath -MailboxName $MailboxName -AccessToken $AccessToken -OneDriveFilePath $OneDriveFile$rtArray = @()$rtArray += (New-referanceAttachment -Name[...]



Simple scripted download Attachment using the Graph or Outlook Rest API in Office365

2017-07-05T18:25:26.122+10:00

This is a rewrite of one of the more popular EWS posts (original post) on my blog about creating a scripted process that would download attachments from an email with a particular subject line in the Inbox and then mark that email read and move it to another folder in the Mailbox. In this post I'm going to go through a direct one to one rewrite of this script and talk about the comparisons between how you used the operations in EWS and now how you can do the same thing using the Graph or Outlook REST API. In another post I'll show an enhanced version that allows you to use the Graph API to save the attachment into another Graph endpoint such as OneDrive or SharePoint.For this script I'm using the Exch-Rest Module I'm currently building which is available on the powershellgallery https://www.powershellgallery.com/packages/Exch-Rest and the source from Github https://github.com/gscales/Exch-Rest. For this script I had to overcome an issue with the ConvertFrom-Json Cmdlet which has an issue once the JSON payload gets over 2 MB so an alternate method in the REST code was needed to allow for attachment downloads of over 2MB.Step 1: Loading the Module, Setting up variables for the script and Getting the Access TokenImport-Module Exch-Rest -Force$MailboxName = "user@domain.onmicrosoft.com"$Subject = "Daily Export"$ProcessedFolderPath = "\Inbox\Processed"$downloadDirectory = "c:\temp"##Get the Access Token$AccessToken =  Get-AccessToken -MailboxName $MailboxName  -ClientId 5471030d-f311-4c5d-91ef-74ca885463a7 -redirectUrl "urn:ietf:wg:oauth:2.0:oob" -ResourceURL graph.microsoft.com  The first step in the scripted process is to load the module then setup some variables to hold which mailbox to access, the subject of the Message to search for and the folder to move the message to once its has been processed. Then finally we have the code to get the oauth AccessToken,with getting the Access Token there are few different options described here you need to choose the most appropriate one for you depending on how you are going to implement this in your environment. The EWS equivalent here would have been loading the Managed API, authenticating and doing an AutodiscoverStep 2: Search for the Items in the Inbox that are Unread, Have Attachments and the Subject line "Daily Export" $Filter = "IsRead eq false AND HasAttachments eq true AND Subject eq '" + $Subject + "'"$Items = Get-FolderItems -MailboxName $MailboxName -AccessToken $AccessToken -FolderPath \Inbox -Filter $FilterIn the REST API like EWS there are two different ways of searching for itemsFilter In EWS this was done using the SearchFilters Class (or a restriction in EWS proxy code) in REST this is done using the OData parameter $filter. The underlying mechanism the Exchange store uses for both EWS and REST to filter items and returned results is based on Restrictions (I still like the explanations in this article as to how they work https://technet.microsoft.com/en-us/library/cc535025(v=exchg.80).aspx) . Using Filters gives you the most flexibility when it comes to finding particular items based on particular properties but this does come at the cost of performance. You should try not to over complicate your filters too much as like any database your performance and application will suffer if the filters are written poorly with no regards to data structure or quantity.Content Index SearchesIn EWS a content index search could be done using AQS (Advan[...]



Using the Office365/Exchange 2016 REST API to access Mailbox data using PowerShell part 5 Sending

2017-06-09T21:16:47.382+10:00

Following on from my previous posts in this series, I've made a number of changes to the Exch-REST PowerShell  module to increase its functionality.The first is that it now supports using either the Microsoft Graph endpoint or the Outlook REST endpoint which has been default so far. If you want to know which endpoint you should use have a look at https://dev.office.com/chooseapiendpoint . The advantage of utilizing the graph endpoint is that it allows you to hook into all the other Office365 services like Groups,OneDrive,SharePoint, Onenote etc using the same endpoint and token (I'll have some example in future posts).To utilize the graph endpoint is easy all you need to do is add one additional parameter when you create the token to specify you want the AccessToken for the graph eg$Token = Get-AccessToken -MailboxName mailbox@domain.com ` -ClientId 5471030d-f311-4c5d-91ef-74ca885463a7 ` -redirectUrl urn:ietf:wg:oauth:2.0:oob -ResourceURL graph.microsoft.com All the other cmdlets will then look at the AccessToken`s resource property using the new Get-Endpoint function and return the appropriate endpoint. If you want to use the preview endpoints you would need to tweak this function to return the appropriate preview endpoint.function Get-EndPoint{        param(        [Parameter(Position=0, Mandatory=$true)] [psObject]$AccessToken,        [Parameter(Position=1, Mandatory=$true)] [psObject]$Segment    )    Begin{        $EndPoint = "https://outlook.office.com/api/v2.0"        switch($AccessToken.resource){            "https://outlook.office.com" {  $EndPoint = "https://outlook.office.com/api/v2.0/" + $Segment }                 "https://graph.microsoft.com" {  $EndPoint = "https://graph.microsoft.com/v1.0/" + $Segment  }             }        return , $EndPoint            }}The only quirk I've come across with the difference between the two endpoints is when using extended properties the Name used to identify the Property is PropertyId in the REST endpoint and Id in Graph Endpoint (when making GET). The module has partial coverage for this but its an area that needs some work and will improve with future updates.I've also added one more AccessToken creation function that allows you to pass in the username and password via a PSCredential. This requires that you have implicit authentication enabled in your app configuration manifest see oauth2AllowImplicitFlow I've also added functions for Item Creation, Sending messages and Attachment enumeration and downloading and it now stores the Tokens in securestrings.Also thanks to Elijah Gagne there is also some proper getting started documentation in the GitHub Repo  https://github.com/gscales/Exch-Rest/blob/master/README.mdI've added some samples for using the Send-MessageREST function which is what you would use when you want to send a Message. This function covers all the Send Message bases it can send a Message normally as a user, Send a Message On Behalf or Send[...]



Mailbox Automapping forward and reverse map using Autodiscover and PowerShell

2017-05-22T21:50:56.392+10:00

Auto-mapping was a feature that was introduced in Exchange 2010, where when you added Mailbox access permission via Add-MailboxPermission, Outlook would automatically add that Mailbox as an additional Mailbox. Outlook uses Autodiscover to get the information on these mailboxes that are auto mapped via the AlternateMailboxes user setting eg in XML it comes back like the following


One thing you can't see easily via the Exchange Managed Shell cmdlet is which ACE's (Access Control Entries) have Automapping enabled on a particular Mailboxes DACL and which don't. You also can't easily see from one mailbox which mailboxes will be auto mapped to it (basically a reverse mapping).So the purpose of this script is to provide both a forward and reverse mapping of Automapping setting for a collection of Mailboxes that are passed into to. It produces a report that look like




To get this collection you can either use a CSV file of addresses, Get-Mailbox or just a static list.

Eg to run the script using Get-Mailbox

create a blank collection
$Mailboxes = @()

populate the collection
Get-Mailbox -ResultSize Unlimited | foreach-object{$Mailboxes += $_.PrimarySMTPAddress}

then run the script like

 Get-AutoDiscoverMailboxMap -Mailboxes $Mailboxes

The report is outputted in the last line of the script.

I've put a copy of this script on GitHub here https://github.com/gscales/Powershell-Scripts/blob/master/AutoDiscoverMap.ps1



Using the Office365/Exchange 2016 REST API to access Mailbox data using PowerShell part 4

2017-05-09T21:01:15.743+10:00

This is part 4 of my ongoing series for using the new REST API in Office365 and Exchange 2016. To make the module I created in previous posts a little more easier to use and open it up for other people to contribute to, I've published the module to the PowerShell Gallery and a new GitHub repository for contribution here https://github.com/gscales/Exch-Rest. So to install the latest version of the module from the PowerShell gallery on Windows 10 you just need to use

Install-Module Exch-Rest which will pull the latest version down from the Gallery

then Import-Module Exch-Rest to load the module

(For Windows 8.1 see http://go.microsoft.com/fwlink/?LinkID=746217&clcid=0x409 )

I've changed the authentication functions to allow you to pass in the ClientId, TenantId and RedirectURL to make it easier to use rather then having to use static variables. The documentation still needs a lot of work.

New functions I've added recently


Get-UserPhotoMetaData

     Gets the user's photo Metadata

Get-UserPhoto

     Download the largest UserPhoto

Folder Operations

New-Folder

    Creates a New Mail Folder (you can also create folder of a subclass of IPM.Note)

New-CalendarFolder

    Creates a New Calendar Folder

New-ContactsFolder

    Creates a New Contacts Folder

Rename-Folder

   Renames an existing folder

Update-Folder

    Updates an existing folder

Invoke-DeleteFolder

   Deletes and existing Mailbox Folder

Set-FolderRetentionTag

  Set a Personal retention Tag on a Folder this uses the Extended properties simular to this EWS script https://blogs.msdn.microsoft.com/akashb/2011/08/10/stamping-retention-policy-tag-using-ews-managed-api-1-1-from-powershellexchange-2010/

Extended property support




Using the Office365/Exchange 2016 REST API to access Mailbox data using PowerShell part 3

2017-04-25T19:55:55.537+10:00

In Part 1 of this continuing series I looked at the basics of accessing a Mailbox using the new REST api in PowerShell with Exchange and in Part 2 accessing all the mailboxes in a tenant as an Administrative application using Certificate authentication. In this installment I've expanded the REST PowerShell module to encompass most of the common data operations like enumerating Folder and Items.Getting a folder from PathA common thing you might want to do with a script that accesses a Mailbox is access a non default folder eg say a folder that a user or application has created in the Inbox. To access a folder with the REST api you need to first know the Id of that particular folder. With the WellKnownFolders in a Mailbox you can use the constants such as Inbox,SentItems etc but for non default folders you need some code that will first find the Id of the Folder by searching for the folder in question in each of the parent folders. I've added a function in the Rest module called Get-FolderFromPath which will take the Path of the folder you want to access and break down and search for each of the folder in the Path and then return the target Folder egEnumerating the Folders in a MailboxIf you want to enumerate all the Folders in a Mailbox in EWS you could do a deep traversal with the  FindFolders operation which would return all the folder paged in lot of 1000. With the REST API you need to traverse each of the ChildFolders separately to return all the folders. With Exchange in EWS there where 4 different strongly typed Folder objects Mail, Tasks, Contacts and Calendar, with EWS all of these where returned with the FindFolder operation. However with the REST API only Mail Folders are returned. With the Calendar, Contacts and Tasks folder you need to use the endpoints for those folder types which also have different permissions associated. This is done so you can have apps that can access all the calendar or contact folders in a Mailbox without the need to have permissions to traverse the Mail folders (and via verse).So if your migrating an existing script its going to requires a slightly different approach from what you may have traditionally done in other API's when doing this type of enumeration.For enumerating all the Folders in a Mailbox I have created the Get-AllMailFolders function which also appends in the FolderPath as a value add egEnumerating Items in a FolderOnce you have retrieved a folder the next logical thing most people want to do is enumerate the Items in that Folder. To do this I've created a few different functions in the module the most common of those is the Get-FolderItems function. This function will either take the JSON Folder object or the path of the folder you want to access and then return each of the Items so you can use it like the followingthis function handles paging of the folder Items in 1000 Item pages with involves using the @odata.nextLink return value and $Top and $Skip tokens from the response.Enumerating All Items in a MailboxOne of the things the REST API exposes easily that EWS didn't is the ability to enumerate all Items in a Mailbox using the AllItems WellKnowFolder name. I've created a function that exposes that endpoint for the AllItems folder eg Get-AllMailboxItems -MailboxName gscales@datarumble.com -AccessToken $tkEnumerating Focussed Inbox ItemsThe replacement to Clutter in Office365 as a way of addressing Inbox overload in Exchange is the Focused Inbox which takes advantage of the rapid d[...]



Using the Archive Item operation in EWS

2017-04-06T22:18:54.824+10:00

As there has been a bit of talk about archiving lately and the new Archive Folder vs the Online Archive in Office365 https://support.office.com/en-us/article/Archive-in-Outlook-2016-for-Windows-25f75777-3cdc-4c77-9783-5929c7b47028?ui=en-US&rs=en-US&ad=US and https://www.petri.com/exchange-online-archive-options .I'd though I'd do a post about the Archive Item operation in EWS which was introduced in Exchange 2013 and is an interesting lever for admins to use if they want to look a manually archiving items to a Mailboxes online archive without using Archive Policies. The Archive Item operation is basically designed to allow you to move items from the Primary to the Online Archive more easily instead of having to batch a Move operation. To use this operation you need to enumerate the Items you want to archive (using a search filter or other restriction) and then provide that as one of the inputs for archive Items as longs as the folder where the Items are being archived from. The only real catch I've found when using it is that you need to use Impersonation or the Automated folder creation in the Archive doesn't seem to happen.

I've created a script that allows you to query a Mailbox folder using an AQS query based on the item received date and then invoke the Archive Items operation on those items and put this up on GitHub here https://github.com/gscales/Powershell-Scripts/blob/master/ArchiveItems.ps1

This script requires EWS impersonation https://msdn.microsoft.com/en-us/library/office/dn722376(v=exchg.150).aspx to run

To run the script you pass in the Mailbox you want to run the script against, the FolderPath where the Items exist that you want to archive and the Date of the Items you want to archive from. Eg to archive items older then one year you would run

Invoke-ArchiveItems -MailboxName user@domain.onmicrosoft.com -FolderPath "\Clutter" -queryTime (Get-Date).AddDays(-365)



Using the Office365/Exchange 2016 REST API part 2 buiding an Admin Runner using AppOnly tokens

2017-03-21T20:48:59.330+11:00

This is part 2 in my REST series in which we will look at AppOnly tokens. These are the Tokens you would look to use when you want to write an application or script that would access every mailbox in an Office365 Tenant.  For an Admin or DevOps person looking at what they might want to do with the new REST API this is useful when your looking to write something that will tweak a config setting on all Mailboxes to comply with a certain Organization policy (no matter how insane) or do some custom Item task that isn't supported in any of the Admin cmdlets.To simplify AppOnly tokens as much as I can they are an Oauth Access token that are requested using Certificate Authentication. Then depending on what Application permission scopes have been allowed for the app in Azure egyour script or app will be able to access that particular Mailbox data across all the Mailboxes within your tenant. In EWS if you understood how impersonation worked this is a kind of an equivalent but a lot better from a security perspective. Eg if your just writing a script that needs to keep contacts in sync in a Mailbox (which I've seen and done many times) then you can just assign the "Read and write contacts in all mailboxes" scope for your application and nothing else and that's all your application can do. With Impersonation you effectively gave full access to Mailbox and which could then be potentially exploited and was much derided by security people in general.Setup  There is bit of setup to do before you can use this which can be little complicated but I'll try to simplify the best I can.1. You need to first create a Web Application registration within your tenant using the Azure Management Console (note a native app won't work for this). https://docs.microsoft.com/en-us/azure/active-directory/active-directory-app-registration . For this type of application the SignIn and Auth url isn't important as we are going to be using certificate auth so you can just use something like https://192.168.100.100:8000 eg2. Configure the Application permissions for what you want your application to do eg the below screen again. For my test app I'm going to be using the "Read All Mailbox Setting" scope to create a script that read the Oof Message and timezone setting from all mailboxes passed in. Delegated permission aren't valid for this type of App as they won't be scoped for the this type of Access token.Make sure you click save down the bottom to ensure the changes you make are committed3. Create a self signed certificate that will be used to sign the JWT (Java Web Token) requests. To make this easy in my Rest module I've create a cmdlet to do this using the default New-SelfSignedCertificate Powershell cmd. However this will only work on Windows 10 because it requires the -provider switch which isn't available on early O/S. Alternatives you can use are MakeCert which there is an example of in https://msdn.microsoft.com/en-us/office/office365/howto/building-service-apps-in-office-365 or you could use OpenSSLIf you want to use my cmdlet you need to use it likeInvoke-CreateSelfSignCert -CertName "yourCertNameMakeitdescriptive" -CertFileName c:\temp\yourcertFile.pfx -KeyFileName c:\temp\KeyCreds.txt where CertName should be self explanatory, CertFileName is the filename for your certificate (you could chose to leave It in t[...]



Using the Office365/Exchange 2016 REST API to access Mailbox data using PowerShell part 1

2017-02-10T19:46:26.191+11:00

The Outlook REST API 's https://dev.outlook.com/ which are part of Office365 and Exchange 2016 is one of the ways new feature are being delivered for Mailbox clients which previously where delivered via EWS operations. They are also part of the Graph API https://graph.microsoft.io/en-us/docs which is Microsoft's envisioned unified data access API that has the ultimate goal of allowing you to access all your data endpoints via a single interface/endpoint.In this series of posts I'm going to be looking at writing a PowerShell module that uses the REST API to access Mailbox data and some of the new Exchange features like Groups and the focused Inbox. To keep things simple and flexible I'm not going to use any helper libraries (like the ADAL library or the Outlook Services Client) which I hope will make the script as portable and easy to use as possible with the one downside of while making the code a little more complex  I'm going to use the System.Net.HttpClient classes for greater flexibility as apposed the native PowerShell Rest interfaces.Getting startedCompared to EWS where there was very little up front configuration necessary to get going (eg in most case just supply a username and password) for the REST API's there is a little bit of configuration that needs to be done.To use the new REST endpoint you need to use oAuth authentication which means instead of a username and password being included as a header which each request to the server like in Basic Authentication you use an Access Token which is only valid for an hour. A Refresh Token can be used to renew the Access Token when it expires. Tokens offer a big security advantage over using a UserName and Password but still should be treated as if they where a username and password in regards to storage and access as they can still be exploited in the same way. This is an extreme simplification of the oAuth, there is some good documentation sources but be careful of those that discuss Modern Authentication and the ADAL library as they tend to abstract away some the real technical side of understanding what's happening with Token Auth. Personally I like https://docs.microsoft.com/en-gb/azure/active-directory/develop/active-directory-authentication-scenarios and https://msdn.microsoft.com/en-us/office-365/get-started-with-office-365-management-apis as these look more at the underlying way the protocols work.To use oAuth to authenticate you need to create an Application registration (which gives you the clientId) to use for your scripts or authorize somebody else's (which wouldn't be recommended).  There are plenty of good walk throughs on creating app registrations using the Azure console this one is quite good https://github.com/jasonjoh/office365-azure-guides/blob/master/RegisterAnAppInAzure.md . For scripting generally you want to create a Native App registration and use the Out of Band Call-back urn:ietf:wg:oauth:2.0:oob . One of the big advantages of using oAuth with the new REST interfaces is the authentication scopes which allow you to restrict an application/script to just being able to access the resources you want. Eg if this app is going to just access contacts data then you just enable the authentication scope that allows access to contacts data without allows ac[...]



Showing the Recipient history from the Out of Office feature using EWS

2017-01-19T21:01:54.193+11:00

One interesting thing I learnt this week from a mailing list that I knew how it worked but didn't know the detail of was the OOF history feature. This feature has been around for ages and its what Exchange uses to ensure you don't receive more then one copy of an OOF message when you send to a mailbox where the OOF status is enabled. According to this KB https://support.microsoft.com/en-us/help/3106609/out-of-office-oof-messages-are-sent-multiple-times-to-recipients this list has a limit of 10000 entries and can cause problems at times like any feature so it give some details on how to manually clear it. The more interesting part for a developer is the property they mention PR_DELEGATED_BY_RULE (or PidTagDelegatedByRule https://msdn.microsoft.com/en-us/library/ee218716%28v=exchg.80%29.aspx). This property contains a list of all the Email Addresses that this Mailbox has sent an OOF message to while the OOF feature was enabled which is something you could do a few cool things with. Pulling on my Sherlock hat here that property name doesn't sound quite right even through the documentation link I posted confirms the property name and property tag are correct the datatype specified in the documentation is Boolean and in the KB its a Binary Stream. Reading a little a more into what that property is meant to do doesn't quite match its uses here on the FreeBusy Folder but a lack of clear documentation on the actually property means at this point lets write it off as some type of anomaly but the property itself is still of interest. Unfortunately no documentation exists for the actual format of the datastream stored in this property, so we have to rely on the inspection method. Looking at the raw stream it looks like a serialized MAPI stream (eg just a bunch of MAPI properties stored in a binary stream) however its not like other serialized Mapi streams (eg the Autocomplete stream) where you have the normal EmailAddress Mapi properties etc. By inspection it looks more tokenized with the normal Mapi property types. Looking at one of the Email Address values there is prefix token of 3349C842  which appears to be a repeating token before other email address values (generally you expect the MAPI Tag here) followed by 0201 which is the normal MAPI property type for Binary props and followed by a something like 1400 which the length of the property value (stored as Hex) and then for example a value like 676C656E7363616C6573407961686F6F2E636F6D . So given that inspection value I can write a really dumb parser in PowerShell that parses out the Data Stream a Byte at a time in a forward manner find the Tokens for the email addresses which always seems to have a null terminator preceding them and then parse out the Email addresses which would give you a history list of the Email received and responded to while the OOF rule was enabled. Note without proper documentation writing a real parser isn't really feasible but from the little testing I've done the dumb parser seems to work okay. I've put a copy of an EWS script that grabs this property from a Mailbox's FreeBusy folder and then dumps and values from this prop into the PowerShell pipeline on GitHub here https://github.com/gscales/Powershell-Scripts/blob/master/ShowOOFRcpHistory.ps1 to use it use something [...]