Update: Estimating the size of an Exchange (online) Archive

Hi all!

A couple of years back, I created a (very basic) script to help estimating the size of an Exchange Archive by looking at the age of a message and comparing it to time periode you envision to use in the the retention/archive policy. Originally, I believe I had posted the script on my personal OneDrive, but the file since seems to have gone missing.

After a few requests, I decided to upload the file to Github for a few reasons:

  1. You can download it again.
  2. People can contribute to improve the script. As I mentioned earlier, it was a very basic script and not super efficient. Unfortunately, I lack the time to spend much time on it, but that doesn’t mean others can’t and help the community by doing so.

You can find the script here, now. (https://github.com/mvanhorenbeeck/EstimateExchangeArchiveSize)

Please note the script is provided as-is with no warranties. I suggest you test the code before trying it in production as I had to pull this source file from an old repository and it may or may not be the same version as I posted originally.

Good luck!


Blog PowerShell

Exchange Virtual Directory HTML Report

Update 12/09/2016: script updated to version 1.8:

  • Included support for Exchange 2016 CU2+
  • Made some minor changes to the code + output now shows a message if successful/unable to write the html file.

Previous updates in version 1.7:

  • Added more recent Exchange build numbers
  • Updated download location to TechNet Script Gallery

You can download v1.8 here


as a consultant, I regularly come across situations in which I have to troubleshoot an existing Exchange server environment or perhaps have to make an assessment, health report, etc.

Almost every time, I found myself looking up the information from the different (commonly used) virtual directories like: Autodiscover, ActiveSync, OWA, ECP, Web Services, OAB… That’s why I thought it became about time I automated this process so that I didn’t have to type the commands in manually anymore.

The result is a simple script which will query the Exchange Client Access Servers in your environment and will query them for their virtual directory information. Depending on the use of the virtual directory, different object are shown:


Blog Exchange PowerShell

Speeding up retrieval of Send-As permissions

Many Exchange administrators are familiar with the Get-ADPermission cmdlet. In the contrary to the Get-MailboxPermission cmdlet, the Get-ADPermission cmdlet retrieves Active Directory permissions for an object, instead of permission in Exchange itself. For instance, the Get-ADPermission cmdlet will reveal e.g. Send-As permissions whereas the Get-MailboxPermission cmdlet will tell you e.g. who has Full Access permissions on the mailbox.

If you need to do a quick search for Send-As permissions, and for a limited set of mailboxes, you will find that using the Get-ADPermission cmdlet is pretty simple and straightforward:

[sourcecode language=”powershell”]Get-ADPermission <mailbox> | ?{$_.ExtendedRight -like "*Send-As*"}[/sourcecode]

If you are dealing with a large number of mailboxes (e.g. several thousands of mailboxes), using the Get-ADPermission cmdlet can be quite limiting. During recent testing, I noticed the command took anywere from 2-8 seconds per mailbox to complete. In this particular scenario, I was helping a customer to move user accounts from their (old) account forest into the new resource forest.

As part of the process, we would enumerate all mailbox permissions (including Send-As), and check if any of them were assigned to a user account in the account forest. However, because the source environment has tens of thousands mailboxes, the Get-ADPermission approach was not feasible.

Normally, querying AD is not a problem. If you’ve ever written an LDAP query, you probably noticed that most of them complete within several seconds –depending on the result set size, of course. But either way, talking directly to AD should be a lot faster. As such, and given that Send-As permission are assigned to the user account in AD, I figured that using the Get-ACL cmdlet would be best suited.

The first particularity to keep in mind is that, for easy processing, you should change your current location in PowerShell to Active Directory:

[sourcecode language=”powershell”]Import-Module ActiveDirectory
Set-Location AD:[/sourcecode]

Next, you can e.g. run the following command to get the ACL for an object. Notice how I’m using the distinguishedName of the object. Although there are other ways to quickly get the DN for an object, I referred to using the Get-Mailbox cmdlet, because I had to run it earlier in the script anyway:

[sourcecode language=”powershell”]$mbx = Get-Mailbox &lt;mailbox&gt;
(Get-ACL $mbx.distinguishedName).Access

ActiveDirectoryRights : ExtendedRight
InheritanceType       : None
ObjectType            : ab721a53-1e2f-11d0-9819-00aa0040529b
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : EXCHANGELAB\Everyone
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

ActiveDirectoryRights : ExtendedRight
InheritanceType       : None
ObjectType            : ab721a54-1e2f-11d0-9819-00aa0040529b
InheritedObjectType   : 00000000-0000-0000-0000-000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : EXCHANGELAB\UserA
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

ActiveDirectoryRights : WriteProperty
InheritanceType       : All
ObjectType            : 934de926-b09e-11d2-aa06-00c04f8eedd8
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : EXCHANGELAB\Exchange Servers
IsInherited           : False
InheritanceFlags      : ContainerInherit
PropagationFlags      : None[/sourcecode]

The result of the cmdlet will look similar to what you see above. For brevity purposes, I’ve omitted some of the results. Nonethelss, it should give you a good picture of what to expect.

As you can see from the results, there’s a LOT of entries on each object. Because I was solely interested in the Send-As permission, I decided to filter the results based on the ActiveDirectoryRights attribute. Given that Send-As is an ExtendedRight, I used the following:

[sourcecode language=”powershell”]$mbx = Get-Mailbox &lt;mailbox&gt;
(Get-ACL $mbx.distinguishedName).Access | ?{$_.ActiveDirectoryRights -eq "ExtendedRight"}

ActiveDirectoryRights : ExtendedRight
InheritanceType       : None
ObjectType            : ab721a53-1e2f-11d0-9819-00aa0040529b
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : EXCHANGELAB\Everyone
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

ActiveDirectoryRights : ExtendedRight
InheritanceType       : None
ObjectType            : ab721a54-1e2f-11d0-9819-00aa0040529b
InheritedObjectType   : 00000000-0000-0000-0000-000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : EXCHANGELAB\UserA
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None[/sourcecode]

So far, so good. However, none of the entries mentioned “Send-As” anywhere. As it turns out, the objectType attribute contains a GUID which refers to the actual permission. AD stores information about Extended Rights in the configuration partition, in a container unsurprisingly called “Extended-Rights”. Using ADSIEdit, you can navigate to the Send-As Extended Right, and look for the rightsGuid attribute. I’ve checked in various labs and environments, and the Guid always turns out to be ab721a54-1e2f-11d0-9819-00aa0040529b.


Now that we have this information, it is very easy to filter the results from the Get-ACL cmdlet:

[sourcecode language=”powershell”]$mbx = Get-Mailbox &lt;mailbox&gt;
Get-ACL $mbx.distinguishedName | ?{($_.ActiveDirectoryRights -eq "ExtendedRight") -and ($_.objectType -eq "ab721a54-1e2f-11d0-9819-00aa0040529b")}

ActiveDirectoryRights : ExtendedRight
InheritanceType       : None
ObjectType            : ab721a54-1e2f-11d0-9819-00aa0040529b
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : EXCHANGELAB\UserA
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None[/sourcecode]

While benchmarking this approach, we were able to return results for approximately 1-5 mailboxes per second. Quite an improvement over before!

The one caveat is that Get-ACL does not return the same result set (in terms of what attributes are shown) as the Get-ADPermission cmdlet. If all you care about it the permission itself, or if you already have all the other information for the mailbox (e.g. because you previously ran Get-Mailbox), than the speedy approach using Get-ACL might just offer all you need.

Blog How-To's PowerShell

Exchange User Permission Enumeration Script

A few years ago, I wrote a PowerShell script which would enumerate the permissions a user had been given in an Exchange environment. Because of some connectivity issues over on pro-exchange.be, earlier, I decided to post the script to the TechNet gallery and do a little write-up here.

The code for the script might be a little old (or clunky FWIW), but it does the trick. Unlike some other scripts out there, the intention of this script is to find where a user has access to (instead of generating a report that shows you who has access to a specific report). Because of that, the script needs to enumerate all permissions in the environment and go through them one by one. As such, the performance of the script might suffer a little in larger environments; but that’s just a small price to pay.

As some of my other scripts, this script was designed to be dot-sourced. In the future, I’ll update the script to add a little more error handling and remove the requirement to dot-source it.

You can download the script from here.

If you have any thoughts or comments, feel free to post them below!



Blog Exchange PowerShell

[updated: July 20, 2015] Script: putting Exchange Server 2013 into Maintenance Mode

Latest Update:

v1.8 (07/20/2015): fixed a copy/paste error in the script and cleaned up the code to be a little more efficient (removed redundant IF-statement. Published the script to the TechNet Script Gallery for easier download access.


In Exchange 2010 one had the option to put a Mailbox server which was part of a DAG into “maintenance mode” by running the “StartDagServerMaintenance.ps1” script that was included with the product. Likewise StopDagServerMaintenance.ps1 was used to pull a server out of this so-called maintenance state. In fact, this script would move any active mailbox databases to another node in the DAG and mark this server as temporarily unavailable to the other servers. That way, if a failover would occur during the server was in ‘maintenance mode’ you wouldn’t risk that it ended up as a valid failover target.

Exchange 2013 now has the ability to go beyond what was possible before and extend this functionality. You now have the possibility to put an entire server into maintenance mode, meaning that also components like e.g. Transport Service or the Unified Messaging Call Router are temporarily put on hold why you do some work on your server.

There might be various reasons to put a server into maintenance mode. For instance when you need to install software or you want to do some troubleshooting without affecting users that might have a mailbox in an active mailbox database on that server. To facilitate the process, I created two scripts which will automatically put an Exchange 2013 Server in or take it back out of Maintenance Mode.

The manual process

The process for putting an Exchange 2013 server into maintenance mode is relatively straightforward. To enable the Maintenance Mode, you must run the commands below.

If the server is a Mailbox server and before you can disable the transport service, all active queues need to be drained first. To help clearing out the queues, existing messages on the server will be moved to another server. Please note that the TargetServer value has to be a FQDN:

[sourcecode language=”PowerShell”]Set-ServerComponentState -Component HubTransport -State Draining -Requester Maintenance
Redirect-Message -Server -Target &lt;server_fqdn&gt;

If the server is part of a DAG, you must also run these commands:

[sourcecode language=”PowerShell”]Suspend-ClusterNode
Set-MailboxServer -DatabaseCopyActivationDisabledAndMoveNow $true
Set-MailboxServer -DatabaseCopyAutoActivationPolicy Blocked[/sourcecode]

Once all queues are empty, you can disable all components:

[sourcecode language=”PowerShell”]Set-ServerComponentState -Component ServerWideOffline -State Inactive -Requester Maintenance[/sourcecode]

Taking the server out of Maintenance Mode is a matter of simply reversing the actions we took to put it into Maintenance Mode.

First, we reactive all components:

[sourcecode language=”PowerShell”]Set-ServerComponentState -Component ServerWideOffline -State Active -Requester Maintenance[/sourcecode]

If the server is part of a DAG, you need to reactive it in the cluster (by resuming the cluster node):

[sourcecode language=”PowerShell”]Resume-ClusterNode
Set-MailboxServer -DatabaseCopyActivationDisabledAndMoveNow $false
Set-MailboxServer -DatabaseCopyAutoActivationPolicy Unrestricted[/sourcecode]

If the server is a Mailbox Server, the transport queues need to be resumed as well:

[sourcecode language=”PowerShell”]Set-ServerComponentState –Identity -Component HubTransport -State Active -Requester Maintenance[/sourcecode]

Although not explicitly required, it’s best to restart the transport services after changing their component states. This ensures they ‘pick up’ the changed component states immediately rather than having to wait for Managed Availability (Health Service) to take action.

Using the scripts

Sometimes it can take a while before active queues are drained. Because I do not always want to wait in front of the screen and periodically check the queues myself, I created two little script that fully automate the process explained above. Besides the required steps, the scripts also perform additional safety-checks and inform you about other server component states which might prevent a server from working correctly.

The first script, Start-ExchangeServerMaintenanceMode.ps1 will put a server into Maintenance Mode, whereas Stop-ExchangeServerMaintenanceMode.ps1 can be used to take a server out of the maintenance state.

Please note that the scripts rely on built-in Exchange functions and therefore need to be run from the Exchange Management Shell.

Version history

v1.8 (07/20/2015): fixed copy/paste bug; removed duplicate code and made some overall improvements to script efficiency.

v1.7 (07/08/2015): removed the requirement to dot-source the script. Published the script to the TechNet Script Gallery for easier download access.

v1.6 (29/11/2013): some minor bug fixes in the Start-ExchangeMaintenanceMode script.

v1.5 (28/11/2013): Based on feedback from several readers, I’ve improved the scripts by rewriting parts of the code and, as such, making it more lenient and more usable in scenarios where you want to run the script from a remote Exchange server. The script now also restarts the Transport service(s) after changing their component states. This ensures that the new component states are picked up immediately, rather than after Managed Availability kicks in. Without the change it could take anywhere from a few minutes to a few hours before the transport services were really inactive/active again. The download links at the bottom of the page are updated to point to the new versions of the scripts. Last, but not least, when ending a maintenance mode, the script will query the server for any components that might still be inactive and display a warning if any are found. A special thanks to Dave Stork for some of the ideas!

v1.4: update the script to include some additional error checks. First it will check whether the person who is executing the script has local admin rights. If not, the script will throw a warning and exit. Secondly it will also check whether the TargetServer name can be resolved. If it’s not an FQDN, it will resolve it to an FQDN. If it cannot be resolved, an error will be thrown.

v1.3: after some feedback from Brian Reid (thanks Brian!), I’ve finally updated the script to include the “Redirect-Message” cmdlet. This will ensure that the queues will drain more quickly on the server by moving messages from one server to another. Have a look at Brian’s blog if you need more info: http://blog.c7solutions.com/2012/10/placing-exchange-2013-into-maintenance.html

v1.2: Maarten Piederiet emailed me pointing out that he had encountered some issues while using the script. Apparently, while draining the message queues, the script ran forever because it waits for every queue to become empty; including Poison- & Shadow Redundancy queues. To avoid this from happening, he made a minor change to the script to now excluded both queues. Thanks for the tip!

The scripts

Below you find links to my SkyDrive from where you can download the scripts. Enjoy!

Start-ExchangeServerMaintenanceMode (v1.8)

Stop-ExchangeServerMaintenanceMode (v1.5)

Disclaimer: these scripts are provided “as-is” and are to be used on your own responsibility. I do not and cannot take any reliability for the use of these scripts in your environment. Please use with caution and always test them before use.

If you have suggestions, comments or think things can be better: please let me know! Your feedback is greatly appreciated!

Blog Exchange PowerShell

Azure AD Synchronization HTML Report

In 2013, Exchange Server MVP Mike Crowley wrote a script which would interactively report on the Office 365 Directory Synchronization tool. In 2014, Mike and I worked to update the script so that an HTML report would be generated. This would allow you to schedule the script and have the output emailed to you without the need to run the script interactively.

Before you can actually run the script, you will have to install SQL PowerShell on the AADSync machine first. DirSync had this installed by default, but it seems that AADSync does not. To install the SQL PS module, you must install the following components separately:

  1. Microsoft® System CLR Types for Microsoft® SQL Server® 2012
  2. Microsoft® SQL Server® 2012 Shared Management Objects
  3. *Microsoft® Windows PowerShell Extensions for Microsoft® SQL Server® 2012

The binaries can be installed from the installation instructions on the following page: http://www.microsoft.com/en-us/download/details.aspx?id=29065

Once you have installed the components, run the following command from the AADSync server and verify that the SQLPS module is listed:

Get-Module -ListAvailable

Once you have verified the SQLPS module is installed and available, you can run the script.

This time around I have decided to publish the script through Github. You can download it from HERE. Alternatively, the script also available from the Technet Script Gallery, HERE.

Please use the script for what it’s worth, and always test in a lab first. Comments/feedback and feature requests are always welcome!

Blog Office 365 PowerShell

Some thoughts on using the Exchange Integration Pack for Orchestrator…

Recently a customer decided to start using System Center Orchestrator to automate some of the recurring tasks with regards to the management and support of their Exchange organization. More specifically, they wanted to create a custom interface to which the support organization would get access to in order to request specific actions like mailbox moves, message tracking logs etc. This would allow them to execute some (basic) tasks themselves without needing any Exchange permissions or being forced to use PowerShell or the Exchange Management Console.

In fact, Orchestrator is very powerful when it comes down to automating things like this. The Integration Packs for products like Exchange, Active Directory and SharePoint allow you to easily develop such solutions.

What is described below are merely some thoughts I had while building the solution along with a colleague of mine. I’m in no way an expert in the use of Orchestrator, but that’s why I thought this information might be interesting to you.

Before diving into the quirks which may (or may not) be “by design”, let’s have a look at what we were trying to build.

The solution

The customer wanted to have a custom interface (not specified what it needed to be) which would allow members of the Service Desk to request message tracking information without the need for an Exchange administrator to intervene. After some debates on whether or not PowerShell should be leveraged to develop such a GUI, we decided to move forward using SharePoint lists. SharePoint lists are easy to setup and use and because it was already heavily used within this organization, it seemed like the logical step.

In order not to complicate things, we decided that we would ask the support engineer for the following information:

  • Sender Email Address
  • Recipient Email Address
  • Date + Time (hour)

 To enter the information into the SharePoint list, a custom form was created which also took care of data validation. As such, the engineer would be able to enter only a sender address, a recipient address or both. The date + time are always required and needed to be in a specific format (yyyy-mm-dd). The reason why we chose to do data validation in the form is two-fold. First, it’s extremely easy to do and secondly, it would save us quite a bit of code later on when building the solution in Orchestrator. The date + hour indication are used to indicate for what time the message tracking logs are requested. We found that 95% of all requests all were within a 24 hour timespan. That’s why the code we built (more about that later) would look in the message tracking logs 12 hours before and 12 hours after the indicated time.

Whenever an engineer would enter a new item in the list, it should automatically get processed by Orchestrator which would then fetch the information from the Message Tracking logs and write it to a CSV file which would be attached to the list item in SharePoint when finished processing.

All-in-all, the requirements were are pretty straight forward which should make the final solution relatively easy to build. In order to meet these requirements, we needed to following components in Orchestrator:

  • SharePoint Integration Pack
  • Exchange Integration Pack
  • Active Directory Integration Pack

Below is a screenshot of the actual runbook which we built:


As you can see, it’s not the most advanced runbook (and maybe not the most efficient either). However, it does the trick. As you will notice, we did built in some logging (in order to have a history what happened) and also do some data validation using the built-in capabilities of Orchestrator.

The quirks

Monitor Item Lists activity

The first problem we came across was using the “Monitor List Items” activity. When first adding this activity to the runbook, it automatically detects all the fields in the list and allows you to use them throughout the runbook as published data from that activity:


The problem, though, is that – for some reason – it doesn’t pick up changes made to the list after the activity has been added to the runbook. When you have designed your SharePoint list to have all the necessary fields from the get-go, this probably isn’t much of an issue. In our case, unfortunately, the customer tends to changes his mind once in a while…
No matter what we tried, newly added fields would not show up in the published data for that activity. The only workaround is to remove the activity and add it again. While this might work for very simple workflows, in larger workflows – like the one above – dealing with this is particularly painful. Especially because the published data from the activity is used in multiple places. This means that when you remove/re-add the activity, you have to go in to all the other activity where you referenced the data and ‘reconfigure’ it. Again, this is not a big problem if you know this up front, but it can cost you some time if you decide to make changes to the SharePoint list. So one word of advice: plan carefully!

Exchange Management Shell code

The Exchange Integration Pack allows you to directly run a bunch of Exchange PowerShell commands when you add the Run Exchange Management Shell activity. Pretty easy, right?!  Not really. As it turns out, not everything you can do in the Exchange Management Shell works in this activity.

For instance, in the Exchange Management Shell, the following code would work beautifully:

[code language=”powershell”]Get-TransportServer | Get-MessageTrackinglog[/code]

Bizarrely enough, this won’t work here. Instead, you have to break the pipeline as follows:

[code language=”powershell”]$servers = Get-TransportServer
$servers | Get-MessageTrackingLog[/code]

My best guess is that the runbook activity is already executing a pipeline which limits what you can do with it. Again, this isn’t a big problem. But it’s just something to keep in mind when developing code to be used in Orchestrator.

Here’s the code I (we) used:

[code language=”powershell”]#Defining Variables

$Subject = "{MT-Subject from "Monitor List Items"}"
$Sender = "{MT-Sender from "Monitor List Items"}"
$Recipient = "{MT-Recipient from "Monitor List Items"}"
$data = "{MT-Date from "Monitor List Items"}"
$Hour = "{MT-Hour from "Monitor List Items"}"

#Check Date Input
[datetime]$inputdate = $date+" "+$Hour+":00:00"
[datetime]$startDate = $inputdate.AddHours(-12)
[datetime]$endDate = $inputdate.AddHours(+12)
$returnMsg = "Input date format invalid"

#Convert DateTimes back into usable format
$strStartDate = $startDate.ToString("yyyy/MM/dd HH:mm:ss")
$strEndDate = $endDate.ToString("yyyy/MM/dd HH:mm:ss")

#Construct cmdlet
$cmd += "Get-MessageTrackingLog -Server `$_.Name"

if($Subject -ne $null -and $Subject -ne ""){
$cmd += " -MessageSubject `"$Subject`""
if($Sender -ne $null -and $Sender -ne ""){
$cmd += " -Sender `"$Sender`""
if($Recipient -ne $null -and $Recipient -ne ""){
$cmd += " -Recipient `"$Recipient`""

$cmd += " -Start `"$strStartDate`""
$cmd += " -End `"$strEndDate`""

#workaround for Orchestrator limitation (limitation while executing pipeline)

$servers = Get-TransportServer
$result = $servers | %{
Invoke-Expression $cmd

$result | Select EventID,Source,Sender,Recipients,MessageSubject,MessageID[/code]

Exchange Management Shell code output

This is probably the biggest quirk we had to deal with. When you execute code within Orchestrator, the output from the code is then pushed to the next activity (provided that you subscribed to the data, of course). In this case, if multiple results came back from the Exchange Management Shell activity, it would fire the following activity for each result. To avoid this and to bundle the results and send them off to the next activity as a whole, you need to “flatten” the output first:


That was easy, wans’t it…? Well, that wasn’t really the problem either. When you take a closer look at the symbol used for separating the results, you’ll notice that we reverted to using a rather rarely used symbol. There’s a specific reason.

Here’s why: for some (stupid) reason, the results which are returned by the EMS runbook activity look like the following:

“[EventId: RECEIVE]
[Source: SMTP]
[Sender: member@linkedin.com]
[MessageSubject: email, please add me to your LinkedIn network]
[MessageId: somethinghere@somethingelse]
,[EventId: SEND]
[Source: SMTP]
[Sender: member@linkedin.com]
[Recipients: email@domain.com]
[MessageSubject: email, please add me to your LinkedIn network]
[MessageId: somethinghere@somethingelse]”

No this is not a weird way of display a hash table, it’s literally a large string which is passed on. This makes it incredibly difficult to deal with. In fact, there is no way that you can just push this into a CSV file and make something useful out of it without dealing with the output first.

A quick look on the internet, brought me to the following article: http://blog.coretech.dk/jgs/scorchestrator-2012-ps-function-for-parsing-the-result-of-the-run-exchange-management-shell-cmdlet-activity/

The author of that article suggested to parse the code and to convert the output into something usable. This seemed fair enough to me and I decided to re-use the code (although I needed to modify it to make it work in our case). This was then added to a second activity called “Convert Output” which is the “Run .NET Script” runbook activity. Here’s the code I used:

[code language=”powershell”]$inputText = "{Command Output for "Get MessageTracking Results"}"

if($inputText -ne ""){

$collection = $inputText.Split("¶")
$returnCollection = @()
foreach ($item in $collection)
$keypairCollection = $item.Split("`n")

$EventID = $keypairCollection[0].Trim().TrimStart("[").TrimEnd("]").TrimStart("EventId: ")
$Source = $keypairCollection[1].Trim().TrimStart("[").TrimEnd("]").TrimStart("Source:").TrimStart(" ")
$Sender = $keypairCollection[2].Trim().TrimStart("[").TrimEnd("]").TrimStart("Sender: ")
$Recipients = $keypairCollection[3].Trim().TrimStart("[").TrimEnd("]").TrimStart("Recipients: ")
$MessageSubject = $keypairCollection[4].Trim().TrimStart("[").TrimEnd("]").TrimStart("MessageSubject: ")
$MessageId = $keypairCollection[5].Trim().TrimStart("[").TrimEnd("]").TrimStart("MessageId: ")

$obj = New-Object -TypeName PSObject
Add-Member -InputObject $obj -MemberType NoteProperty -Name "EventID" -Value $EventID
Add-Member -InputObject $obj -MemberType NoteProperty -Name "Source" -Value $Source
Add-Member -InputObject $obj -MemberType NoteProperty -Name "Sender" -Value $Sender
Add-Member -InputObject $obj -MemberType NoteProperty -Name "Recipients" -Value $Recipients
Add-Member -InputObject $obj -MemberType NoteProperty -Name "MessageSubject" -Value $MessageSubject
Add-Member -InputObject $obj -MemberType NoteProperty -Name "MessageId" -Value $MessageId

$returnCollection += $obj
$output = $returnCollection | convertto-csv -delimiter ";"
[string]$output = "No messages could be found with the specified parameters."

You might still wonder why I had to use the ¶ symbol as a delimeter for the output from the “Get MessageTracking Results” activity… The problem with parsing the code is that you have to split the individual results returned by the activity. Using a regular comma or semi-colon is out of the question as it’s quite likely that the subject for a message contains that same character which would cause the output conversion to fail (I found out the hard way). So we needed to decide on a symbol which allowed us to safely parse the code. Hence the ¶ symbol. For now, this does mean that if someone uses the ¶ symbol in the subject and it is returned by the message tracking logs, the above code will fail and there won’t be any output for the message tracking request.

If you have a better alternative: feel free to comment and let me know!

Some final thoughts

All in all, Orchestrator proves to be quite a flexible platform to perform tasks like the one described in this article. Especially the combination with SharePoint makes it very easy to build ‘custom’ tools which can be used by anyone without needing to provide them with permissions in Exchange (even though RBAC provides a nice framework to do just that). I only wish that some of the quirks got solved as it will remove the need for additional steps (and code) which only add complexity…

Exchange 2013 PowerShell

Create a function to connect to and disconnect from Exchange Online

[Update 26/03/2013] I wanted to share a quick update to the script with you. Over the past few weeks, I have hitting an issue at some customers that used an outbound authenticating proxy which prevented me from connecting to Exchange Online using the functions from my profile. As such, I have tweaked the script a bit to now include a switch (-ProxyEnabled) that, when used, will trigger PowerShell to authenticate the session against the proxy.

The new script now looks like this:

[sourcecode language=”PowerShell”]
function Connect-ExchangeOnline{

$Session = New-Pssession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential (Get-Credential) -Authentication Basic -AllowRedirection -sessionOption (New-PsSessionOption -ProxyAccessType IEConfig -ProxyAuthentication basic)
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Authentication Basic -AllowRedirection -Credential (get-credential)

Import-PSSession $session

function Disconnect-ExchangeOnline {
Get-PSSession | ?{$_.ComputerName -like "*outlook.com"} | Remove-PSSession

[Original Post]

Office 365 allows you to connect remotely to Exchange online using PowerShell. However, if you had to type in the commands to connect every time, you would be losing quite some time:

[sourcecode language=”powershell”]$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri <a href="https://ps.outlook.com/PowerShell">https://ps.outlook.com/PowerShell</a&gt; -Authentication Basic -Credential (Get-Credential) -AllowRedirection

Import-PSSession $session[/sourcecode]

Equally, to disconnect, you’d have to type in the following command each time

[sourcecode language=”powershell”]Get-PSSession  | ?{$_.ComputerName -like "*.outlook.com"} | Remove-PSSession[/sourcecode]

However, it is relatively easy to add both commands into a function which you can afterwards add them into your profile:

[sourcecode language=”powershell”]Function Connect-ExchangeOnline{
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri <a href="https://ps.outlook.com/powershell">https://ps.outlook.com/powershell</a&gt; -Authentication Basic -AllowRedirection -Credential (Get-Credential)
Import-PSSession $session

Function Disconnect-ExchangeOnline{
Get-PSSession  | ?{$_.ComputerName -like "*.outlook.com"} | Remove-PSSession

To add these functions to your PowerShell profile, simply copy-past them into your profile. To find out where your profile-file is located, type the following:

PS C:\> $profile

To start using the functions, all you have to do is to call them from the PowerShell prompt:

PS C:\> Connect-ExchangeOnline

cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:

WARNING: Your connection has been redirected to the following URI:

PS C:\> Disconnect-ExchangeOnline

Note   there is no output for the Disconnect-ExchangeOnline function

How-To's Office 365 PowerShell

Updating the FriendlyName property of a certificate using PowerShell

Update: you actually *can* update the property (even if it’s not there). Seems I was just too blind to notice it earlier. Thanks to Michel De Rooij for pointing this out.

In one of my earlier articles, I wrote about how to integrate Office Web Apps with Exchange Server 2013. As part of that process you had to configure the Office Web Apps farm with the name of the certificate that the farm would use.

The certificate attribute that you have to use is stored in the “Friendly Name”-property of the certificate. Although it’s pretty easy using the MMC (duh!), it’s always nice being able to do something through PowerShell.

According to an article I found, certutil.exe could be used to add a Friendly Name to a certificate. Although CertUtil.exe certainly proved its value in the past, I’m not particularly fond of it either.

Unsurprisingly, the solutions with PowerShell is pretty easy! Using the Set-Location cmdlet, you can change your active namespace to the certificate store:
[sourcecode language=”PowerShell”]Set-Location cert:[/sourcecode]
From there, navigate to the location where the certificate you want to add (or change) the property for. For instance:
[sourcecode language=”PowerShell”]cd .\\LocalMachine\My[/sourcecode]
Using Get-ChildItem we can retrieve a list of all the certificates in the store:
[sourcecode language=”PowerShell”]Get-ChildItem[/sourcecode]

PS Cert:\CurrentUser\my> Get-ChildItem

Directory: Microsoft.PowerShell.Security\Certificate::CurrentUser\my

Thumbprint Subject
---------- -------
FEA21BCDB0FBFC2B00EBE4DA8A524D0C0999FBDC E=michael@vanhorenbeeck.be, CN=michael@vanhorenbeeck.be, Description=fgt8C...
100953EB6F74F5B60937BB0C7329037D9AE9927A CN=xowas.xylos.com, O=DO_NOT_TRUST, OU=Created by http://www.fiddler2.com
070D4C36B95D9550488F4A2DDCEAF76F5B6C7AAA CN=outlook.linkedinlabs.com, O=DO_NOT_TRUST, OU=Created by http://www.fidd...
0224B3E25491F1A7F71D8367B147F41F3C1250D5 CN=www.google.com, O=DO_NOT_TRUST, OU=Created by http://www.fiddler2.com

Once you’ve determined what certificate you want to update, we need to query the certificate and update the FriendlyName property as follows:

$cert = GCI

[sourcecode language=”PowerShell”]$cert.FriendlyName = “FriendlyName”[/sourcecode]

PS Cert:\CurrentUser\my> $cert = gci 070D4C36B95D9550488F4A2DDCEAF76F5B6C7AAA
PS Cert:\CurrentUser\my> $cert.FriendlyName = "FriendlyName"

That’s it! To verify that the property was set successfully, do the following:
[sourcecode language=”PowerShell”]gci
| fl name,FriendlyName[/sourcecode]

PS Cert:\CurrentUser\my> gci 070D4C36B95D9550488F4A2DDCEAF76F5B6C7AAA | fl ThumbPrint,FriendlyName

Thumbprint   : 070D4C36B95D9550488F4A2DDCEAF76F5B6C7AAA
FriendlyName : FriendlyName

Exchange 2013 PowerShell

Retrieving Exchange Autodiscover SCP information from AD via PowerShell

As part of the Autodiscover process, Outlook will query Active Directory in search for the Autodiscover SCP which it will use to discover the Autodiscover URL where it should send its request to.

The configuration information for Autodiscover can easily be retrieved with the Get-ClientAccessServer cmdlet, which will show you important information like:

  • AutoDiscoverSiteScope
  • AutoDiscoverServiceInternalUri
  • WhenCreated

The reason that I’m referring to these three items is because of the way Outlook will handle the retrieved Autodiscover information. In a nutshell, it will query AD and will retrieve a list of SCPs. This list will first be ordered based on the Site Scope (the site in which the client resides). If not, the list will be ordered by creation date (older entries will get queried first).

If you wish to find out more about this process, have a look at the following article: http://technet.microsoft.com/en-us/library/bb332063(v=exchg.80).aspx

What I wanted to do, is “mimic” this process without running the Get-ClientAccessServer cmdlet. One of the reasons is that Get-ClientAccessServer cmdlet depends on the Exchange Management Shell (or more accurately, the Exchange snapin).

Below you will find a code example which uses PowerShell’s ability to query AD directly (ADSI). It will use exactly the same query as Outlook does to retrieve a list of SCPs and will then query these SCPs for the information mentioned above. In the end, the information is displayed on screen, where the SCP records are filtered based on SiteScope and Creation date.

This should give you a pretty good idea of what URL/server your Outlook client will connect to (first) during the AutoDiscover process. Enjoy!

[sourcecode language=”powershell”]
$obj = @()

$ADDomain = Get-ADDomain | Select DistinguishedName
$DSSearch = New-Object System.DirectoryServices.DirectorySearcher
$DSSearch.Filter = ‘(&(objectClass=serviceConnectionPoint)(|(keywords=67661d7F-8FC4-4fa7-BFAC-E1D7794C1F68)(keywords=77378F46-2C66-4aa9-A6A6-3E7A48B19596)))’
$DSSearch.SearchRoot = ‘LDAP://CN=Configuration,’+$ADDomain.DistinguishedName
$DSSearch.FindAll() | %{

$ADSI = [ADSI]$_.Path
$autodiscover = New-Object psobject -Property @{
Server = [string]$ADSI.cn
Site = $adsi.keywords[0]
DateCreated = $adsi.WhenCreated.ToShortDateString()
AutoDiscoverInternalURI = [string]$adsi.ServiceBindingInformation
$obj += $autodiscover


Write-Output $obj | Select Server,Site,DateCreated,AutoDiscoverInternalURI | ft -AutoSize

Exchange How-To's PowerShell