The power of PowerShell: An intro for Exchange admins

Forgo the GUI in favor of the console and free yourself of the drudgery of administering Exchange

Managing Exchange can be a significant time sink, and you may be surprised to find that much of the time spent administering Exchange is pure waste -- unless, that is, you’re already tapping PowerShell.

“Waste?!?” you may be thinking. “I don’t waste any time managing Exchange!” But if you’re diligently attached to the Exchange Admin Center building mailboxes, changing routing groups, restoring email, and so on, you’re spending far too much time clicking around in a GUI. Repetitive tasks are the bread and butter of the PowerShell console. If you aren’t already deeply versed in PowerShell, this hands-on tutorial will convert you.

Windows PowerShell has its roots in Exchange Server. Way back in Exchange Server 2007, the Microsoft Exchange team decided to take a gamble on this new scripting language, and PowerShell has since expanded its reach to nearly every facet of IT. If you’re an Exchange administrator, you’ve probably used PowerShell some. Here, we delve a little deeper, going over a few examples of what you can do in PowerShell with Exchange that will cut down the time you spend on administrative drudgery.

Get connected without RDPing into your Exchange server

To tap the power of PowerShell, you first have to connect to your Exchange server. You could remote desktop onto one of your Exchange servers and fire up the Exchange Management Shell, but I don’t recommend that approach at all. Servers are meant to process workloads, not to power GUIs. Instead, there’s a better way to connect, called implicit remoting.

All the PowerShell functionality that comes bundled with Exchange Server is wrapped up in a PowerShell module. When Exchange is installed, the module is installed on the server, not your admin workstation. Thus, you will need a way to make all of those Exchange PowerShell functions available on your admin workstation. Implicit remoting allows you to do that.

To make use of implicit remoting, you must first establish a remote session to the Exchange server. Once your session is established, you will then virtual import this remote session into your local session, which will make it seem like you’re on the server’s PowerShell console itself.

To create that remote session, we’ll use the New-PSSession cmdlet. Exchange provides specific configuration options for remote sessions, so we’ll need to specify a few more parameters than simply the name of the server and a credential that typically applies to new remote sessions. This means specifying the ConfigurationName of Microsoft.Exchange and a ConnectionUri of http://MYEXCHANGESERVER.MYDOMAIN.LOCAL/PowerShell/?SerializationLevel=Full, subbing in your environment’s server info for what’s in all caps in the URI.

This will create a remote session inside the $Session variable. Once you have this, it’s then a matter of importing that remote session into your current local session by using the Import-PSSession cmdlet.

Import-PSSession -Session $Session

If all goes well, you should see your module output as shown above. You should now have all of the cmdlets available to the Exchange server now available on your local admin workstation. Here is where the real power of managing Exchange with PowerShell begins.

Manage Exchange mailboxes with PowerShell

One of the most common Exchange administrative tasks is managing mailboxes. Your organization probably has more than a few mailboxes, right? Mailboxes have a bunch of common attributes. For example, every mailbox has an assigned username, a quota, set policies, sending limits, and so on. This is where use of PowerShell shines. Let’s say you need to change the quota on 100 mailboxes. That would be painful using the GUI, but it’s pretty easy using PowerShell.

Wherever you find yourself having to perform a certain action on a common set of objects the first place you should look is PowerShell. Let’s go over a few examples.

Find mailboxes

Let’s say you have thousands of mailboxes spread across multiple mailbox servers. Perhaps you need to find some information about one of your user’s mailboxes. Let’s pick on Virginie Jean. To do this, we’d simply use the Get-Mailbox cmdlet, which returns limited, but useful information about mailboxes.

Get-Mailbox -Identity ‘Virginie Jean’

Limited information indeed -- what if I’m looking for an attribute of her mailbox that I don’t see among the above defaults? By using the PowerShell pipeline and the Select-Object cmdlet with an asterisk for the -Property parameter, I can get the full extent of what the Get-Mailbox cmdlet pulls about the mailbox, not only Microsoft’s “friendly” defaults. The screenshot below is a tiny fraction of the information you can glean from Get-Mailbox. There are actually dozens of attributes about the mailbox you can find.

Get-Mailbox -Identity ‘Virginie Jean’ | SelectObject -Property *

Pretty easy -- but what if you need to find information about a lot of users? If all of those users match some kind of pattern you can use the -Filter parameter.

Maybe I want to find all of the mailboxes owned by someone named Adam.

Get-Mailbox -Filter {Name -like ‘Adam *’}

Change mailboxes in bulk

Finding mailboxes is rarely the end of your task. Instead you’ll likely want to do something with those mailboxes after you’ve found them. Here, piping your set of mailboxes to another cmdlet like Set-Mailbox or Remove-Mailbox is key.

What if the owners of all of those mailboxes that start with “Adam” went on vacation and we needed to change the forwarding address? Simple:

Or maybe their owners left the organization, and I want to remove the mailboxes. Simply change Set-Mailbox to Remove-Mailbox and they’re gone.

Get-Mailbox -Filter {Name -like ‘Adam *’} | Remove-Mailbox

Chaining a number of commands together by piping them directly from one cmdlet to another in this way is a powerful way of addressing Exchange admin tasks through PowerShell.

Mailbox statistics and CSV reports

Another common activity that Exchange administrators must do is finding where all that hard-earned storage is allocated. Which mailbox takes up the most space on the SAN, and which folders in that mailbox are taking up so much space? This kind of information can easily be found with PowerShell using the Get-MailboxFolderStatistics cmdlet.

While we’re at it, let’s add another PowerShell cmdlet called Export-Csv to our arsenal. Recall that piping thing we did earlier? That isn’t limited to mailboxes. The pipeline is one of the most powerful features of PowerShell for good reason. In this section, I’ll show you how you can use the pipeline to take data returned from any cmdlet and immediately turn it into a nicely formatted CSV file with little effort.

Using the Get-MailboxFolderStatistics cmdlet you can easily see what items are in a folder, how much space each item takes up, and other useful information. Let’s try the cmdlet on Virginie Jean’s mailbox again.

Get-MailboxFolderStatistics -Identity ‘Virginie Jean’

The above screenshot shows a single object returned from the command, which is the top of the information store. In total, Virginie’s mailbox returned 15 different folders from her calendar, notes, email folders, and so on. Suppose you want to see the mailbox’s calendar only. Simply append the -FolderScope parameter at the end of this command and use the argument Calendar.

You can see that you have a lot of control over the types of folders to look for.

help Get-MailboxFolderStatistics -Parameter FolderScope

You’ve seen an example of a single mailbox, so let’s take this global. How hard it is to search all mailbox folders and get a report on who’s hogging up storage? Get-MailboxFolderStatistics doesn’t have an option to find all mailboxes, so we’ll have to go back to the pipeline again.

Get-Mailbox | Get-MailboxFolderStatistics

This simple command will begin enumerating all mailboxes in your organization. As it’s finding each mailbox, it will then “pipe” the mailbox to Get-MailboxFolderStatistics, where it will begin enumerating all the folders inside each mailbox. Note, however, that by default Get-Mailbox will return only the first 1,000 mailboxes it sees. If your organization has more than 1,000 mailboxes you’ll have to use the -ResultSize parameter to increase the limit. My demo organization has more than 1,000 mailboxes, so I will use this parameter when running the report.

We now have the ability to get all mailboxes and all folders inside the mailboxes. Get-MailboxFolderStatistics returns a lot of different properties for the folders. Since we’re building a space report we don’t need all of them. I only need the mailbox name, folder name, and the size of each folder. To limit my output to these properties I’ll use the Select-Object cmdlet and the -Property parameter. You’ll see in the screenshot below that I’m using the Select-Object alias Select and I’m excluding the -Property parameter, instead choosing what PowerShell calls positional binding.

(Not: This is typed as one line in PowerShell. Due to the line length, it is broken into different lines for formatting reasons.)

I included a few of the objects to give you an example of what you might see. Now we’re getting only the information necessary for the report. Next, I’d like to sort all of the folders by FolderSize. No problem -- we’ll simply pipe the folders into the Sort-Object cmdlet and use the -Descending parameter to ensure we see the biggest folders first.

(Note: This is typed as one line in PowerShell. Due to the line length, it is broken into different lines for formatting reasons.)

Finally, we have the data we’re looking for, but perhaps our manager wants this information and we need to email him. Since this is tabular data, a CSV would be perfect. How can we get this to output as a CSV file? With one more cmdlet and pipe:

(Note: This is typed as one line in PowerShell. Due to the line length, it is broken into different lines for formatting reasons.)

All I had to do was add Export-Csv to the end to send all the output to a CSV file rather than the console. With Export-Csv you’ll use the -NoTypeInformation parameter a lot. If you do not include this parameter, a small line will be included at the top of your CSV that contains text that has nothing to do with the output.

Once it’s done you should then have a CSV file that contains every mailbox identity, name, and the size sorted by largest to smallest.

If you’re curious as to how well it went without opening up Excel, you can easily read the top few rows of the CSV using the Import-Csv cmdlet and Select-Object again. Since the Identity property can get pretty long you can force the rows to fit nicely by ending the pipeline with the Format-Table cmdlet using the -AutoSize parameter.

We covered a tiny fraction of what’s possible when using PowerShell to manage Exchange. If you haven’t been using PowerShell to manage Exchange, I hope this tutorial has inspired you to start. If you’d like to dive deeper into PowerShell and Exchange I recommend checking out "Microsoft Exchange Server 2013 PowerShell Cookbook" by Mike Pfeiffer and Jonas Andresson. It’s a learn-by-example book that gives you tons of recipes for making the most of PowerShell.

Adam Bertram is a 20-year veteran of IT and experienced online business professional. He’s an entrepreneur, IT influencer, Microsoft MVP, blogger, trainer and content marketing writer for multiple technology companies. Adam is also the founder of the popular e-learning tech screencast platform TechSnips. Catch up on Adam’s articles at adamtheautomator.com, connect on LinkedIn, or follow him on Twitter at @adbertram or the TechSnips Twitter account at @techsnips_io.