Why Exchange Admins should learn PowerShell

techtarget_logoAs some of you may or may not be aware of, recently I have joined the ranks of Exchange and The UC Architects fellows Michael van Horenbeeck and Steve Goodman and started writing for the Exchange section at TechTarget.

The first two articles are a call to action for Exchange admins to start working on their PowerShell skills if they have not already done so. Learning can take the more academic approach, starting from scratch and learning the basics topic by topic, or a more practical one by reading and getting to understand existing scripts which may suit the more time-constrained admin.

Read the full articles here and the follow-up article here.

If you got topic suggestions, use the contact form or send me an e-mail.

Regular Expressions and Named Groups

powershellWhen processing strings, you may sometimes need to split those strings into several parts based on criteria. For example, you may need to split the ActiveSync DeviceUserAgent string, which can be used to identify the model and version of a device, for example:

  • Apple-iPhone4C1/1002.142
  • Apple-iPad2C1/1002.141
  • Apple-iPhone4C1/1001.523

Now let’s assume you want to take this string apart in the device model and the version, using the slash as a marker. When asking 10 people, a majority will come up with something along the following kind of structure:

$pos= ($Device.DeviceUserAgent).IndexOf("/")+1
$Device= ($Device.DeviceUserAgent).Substring(0, $pos)
$Version= ($Device.DeviceUserAgent).Substring($pos+1)

Of course, this works but you need to understand what’s going on and additional code is required the handle situations when there’s no “/” present. Perhaps a more elegant and readable way, especially if you want to split the string in more than 2 parts, is using regular expressions to perform pattern matching. When used in combination with named groups, you will get easily referable parts using a name.

For the purpose of demonstrating it’s power, we’ll start by assigning some user agent strings to a variable. Note that you could use the DeviceUserAgent property of a collection of ActiveSync devices as well.

$UserAgents=@("Apple-iPhone4C1/1001.523", "Apple-iPhone3C1/801.293")


The pattern to look for in each user agent string is it starts with some characters, followed by a slash, followed by a number, followed by a dot and ending in a number. Translated to regular expression, the pattern would be:



  • ^ marks the start of the subject;
  • (.*) marks a sub pattern of any character, the * indicates it’s present zero, one or more times;
  • The slash is marked by (surprise!) a /;
  • (\d+) marks a sub pattern of decimal digit, the + indicates it’s used one or more times;
  • \. will match the dot (escaping it with “\” makes sure next character is used literally as ‘dot’ normally means any character);
  • $ marks the end of the subject.

When matching a pattern against a string you can use –match, e.g. “string” –match “pattern”. When this results in True, a match is found; when the result is False, the format of the string is invalid (of course requires properly defined pattern). After performing a match, the predefined variable $matches will contain an array containing the results, where element [0] contains the complete matching string and [1] .. [n] each matching (sub) pattern.


You see that each match returns True (match found) and $matches[1] for example contains the first sub pattern for each match, i.e. the device. This is nice and perhaps neater than splitting strings as mentioned in the start of this article, but wouldn’t it be even cooler if you can refer to those parts using names, e.g. device?

Here’s where named groups come into play and you can compare it to PowerShell’s calculated properties (select @{Name=”KB”; Expression={$_.Size/1kb}}) or column aliases in SQL (SELECT ColA as Name). To use named groups, put “?<name>” at the start of the (sub) pattern. For example, to use the name “device” for the first sub pattern “(.*)”, the expression would become “(?<device>.*)”. The complete pattern using named groups would then become something like:


The cmdlet for this example would then become:

$UserAgents | ForEach { [void]($_ -match "^(?<device>.*)/(?<major>\d+)\.(?<minor>\d+)$"); $matches }

Which will give the following results:


Note that I’ve added casting (i.e. converting a variable to a different type) the output of “-match” to [void] so the match results (True or False) won’t be part of the output.

Having named groups now allows us to use easily match individual parts, filter or group information, e.g.:

$UserAgents | ForEach {
    [void]($_ -match "^(?<device>.*)/(?<major>\d+)\.(?<minor>\d+)$")
    If( $matches.major –gt 800) { 
        echo $matches[0]

Of course it’s a matter of taste, but having this information available as $matches.device instead of $matches[1] makes introducing changes more easy (no need to renumber when inserting/removing a sub pattern) and results in more readable code.

NGN Exchange Event, Tips & Tricks Presentation

On October 31st, the NGN – a Dutch society for IT professionals – held its 3rd Exchange themed event, this time at The Reehorst in Ede (NL). Because of the recently released Exchange 2013 and all the news and related questions, we planned for a whole day of sessions and it was nice to see the turn up was nearly 100 IT professionals.

Since all people would still be on pre-2013 versions of Exchange, I figured a presentation using real-world Exchange 2010 Tips and Tricks might be more appropriate. I was glad a quick poll amongst the attendees showed a significant increase in Exchange 2010 deployments (around 80%) when compared to last year’s event, but as expected there’s still some Exchange 2007 and few Exchange 2003 out there.

I decided to stick with two deep-dive topics, which were Message Trackings Logs and Cmdlet Extension Agents. On those topics I went from basics to more advanced examples, hoping it would ignite people with no experience and people with experience could still pick up a thing or two.I’m still waiting for evaluation results, the only way to get feedback from these sessions apart from the occasional e-mail or tweet.

(picture by Dave Stork)

You can find my presentation here (partially Dutch) and the accompanying sample script on Message Tracking Logs here and the one on Cmdlet Extension Agents here (script); the ScriptingAgent.xml file can be downloaded here.

As always, these events are also a time to catch up with fellow Exchange people and discuss topics with attendees during the breaks. There were even Exchange fellows present who didn’t have a session, like Johan Veldhuis (MVP) and Maarten Piederiet (MCM); they did join in on the Q&A Panel.

The sessions and speakers were:

  • Introduction (Jaap Wesselius, MVP)
  • Building with Exchange 2013: Architecture (Dave Stork)
  • Exchange and Virtualisation (Jetze Mellema)
  • Exchange 2010 Tips & Tricks (Ashley Flentge, MCM & Michel de Rooij)
  • Exchange 2013 Coexistence and Migrations (Kay Sellenrode, MCM and MCA)
  • Exchange and Load Balancing (Jetze Mellema)
  • Q&A Panel

The NGN published all presentations in a single ZIP file which can be downloaded here. Unfortunately, NGN didn’t record the sessions so I can’t share those with you. They did record the Q&A Panel session; you can view it here (in Dutch):

PS: When you see references to “exchangedag”, like in the Twitter hashtag, you need to know “dag” means day in Dutch; it’s no form of professional deformation.

Adding Exchange Shell items to PowerShell ISE

I’ve become a fan of using the PowerShell Integrated Scripting Environment (PowerShell ISE) for creating, testing and debugging scripts, using breakpoints and step-by-step execution; features found in many development environments. Depending on the script I’m working on and for what customer or environment, I may need to add snap-ins or switch contexts, like connecting to Exchange Online.

One of the powerful features of ISE is that it allows customizing through the ISE object model. For example, you can explore ISE through the $psise object:


To add custom menu options to ISE, we’re going to add items to the submenu of $psISE.CurrentPowerShellTab.AddOnsMenu, which is “Add-ons”. An item needs to consist of:

  • Display Name, which is used for displaying the menu item;
  • Action, which can be a PowerShell cmdlet, scriptblock or function;
  • Optionally, you can assign a keyboard shortcut to the menu option.

To automatically load the custom entries after starting up ISE, we’re going to define the entries in our default ISE profile file, Microsoft.PowerShellISE_profile.ps1, which location is stored in $profile. The file doesn’t exist by default, so when required you can simply create the file in the proper location using notepad $profile.

In our example, we’ll add three entries:

  • Implicit Remoting to connect to Exchange using a static FQDN;
  • Loading the Exchange 2010 Snap-in and connecting to Exchange using Autodiscover (unsupported, will bypass RBAC);
  • Connecting to Exchange Online.

Note that the example won’t be using stored credentials and will let ISE prompt the user for credentials when required, which is perfectly fine if you need to access different Office 365 tenants for example.

Now, in the Microsoft.PowerShellISE_profile.ps1 file, add the following contents:

    "Connect to Exchange @ Contoso", {
        $ExSession= New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://exserver.contoso.com/PowerShell/ -Authentication Kerberos
        Import-PSSession $ExSession
    "Connect to Exchange On-Premise", {
        Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
        . $env:ExchangeInstallPath\bin\RemoteExchange.ps1
        Connect-ExchangeServer –auto
    "Connect to Exchange Online", {
        $o365Cred= Get-Credential
        $o365Session= New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $o365Cred -Authentication Basic -AllowRedirection
        Import-PSSession $o365Session

After starting ISE you’ll see the Add-ons menu now contains three extra items:


When selecting “Connect to Exchange Online” (or pressing the configured keyboard shortcut), ISE will execute the associated code block; the progress is displayed in the output window. You will be prompted for credentials after which ISE will connect to Exchange Online and import the remote session.


After the session has been imported, you have the additional commands at your disposal in ISE and you can work on your scripts since they’ll be running in the context of the environment you’ve connected to.

Of course, this is just an example of what you can customize in ISE (pink background anyone?). For more information on customizing PowerShell ISE check here. If you’re new to PowerShell ISE, check here.

TechEd North America 2012 sessions

With the TechEd North America 2012 event still running, recordings and slide decks of finished sessions are becoming available online. Here’s an overview of the Exchange-related sessions:

Exchange & PowerShell Presentation (Dutch)

After last years NGN Exchange event, where I presented a session on Exchange Autodiscover,  it was time for a followup. This event took place on May 19th and had a turn up of about 80 attendees, which was better than expected given the fact this was a non-free NGN event unlike last year. Early questions indicated large part of the attendees are still on Exchange 2003, though the figure has dropped a bit from last year’s 80%.

I held a duo-presentation with Maarten Piederiet on the topic PowerShell and the Exchange 2003 Administrator. A fingers up poll also showed lots of people still working with batchfiles, VBScript or KiXtart. This was expected, so our topic was spot on since we included PowerShell primer topics. Of course, this 45 minute session doesn’t replace a proper PowerShell course, let alone a course for decent development skills but our goal was to get people enthusiastic by demonstrating how simple yet powerful PowerShell is.

Besides presenting, which went a lot better than last year on a side note, it was also a time to catch up with fellow Exchange MVPs and enjoy discussions with attendees during the Ask The Expert breaks.

Below you’ll find the presenters’ slidedecks in PDF format. Note that the presentations are in Dutch.

Unfortunately, NGN decided not to publish the recorded sessions so I can’t share those with you.

Remote PowerShell to Office 365

imageWhile trying Office 365 you might want to connect your to a remote Exchange Management Shell session instead of using the portal interface. Here’s how to proceed.

Start up a PowerShell session. The first thing we’re going to do next is store credentials in a variable for later usage:

$cred= Get-Credential

A popup will be displayed where you can enter your Office 365 admin credentials, e.g. myadminname@yourdomain.onmicrosoft.com.

Next, create a new remote PowerShell session using the following cmdlet:

$o365= New-PsSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $cred -AllowRedirection -Authentication Basic


Next, we can import the session. However, this might be confusing since you have no context; are you creating a mailbox local or in the Office 365 environment?

The cool thing is that with Import-Session you can specify a prefix. This prefix can be specified before the cmdlet noun so that PowerShell knows which session you want the cmdlet to run against. As you probably know, cmdlets are normally constructed using <verb>-<noun> syntax, but this should be <verb>-<session prefix><noun>. When the session prefix is omitted, PowerShell assumes the current session.

For example, let’s import our Office 365 session with a prefix of “o365”:

Import-PsSession $o365 –Prefix o365


Now, we can use that “o365” prefix before the noun. For example, to get a list of our Office 365 mailboxes, you’d use something like:



Cool and simple, eh?

Don’t forget to close your online session afterwards using:

Remove-PsSession $o365

Have fun exploring Office 365 using PowerShell.