Tag Archives: exchange


Connecting to Exchange Online Using Multi-Factor Authentication via PowerShell

Using PowerShell to manage your Microsoft cloud services like Exchange Online is awesome. Using multi-factor authentication (MFA) is also awesome. For some reason, using the two together is not awesome. Many of the Microsoft docs on this seem to suggest you just perform all your administrative tasks from a shell that you launch entirely separately from a normal PowerShell console. I would rather be able to connect to Exchange Online using MFA via PowerShell through a normal console, or as part of another tool. Let me show you how.

Continue reading


Using PowerShell To Add Groups To “AcceptMessagesOnlyFromDLMembers” Exchange Attribute

Here’s a bit of an obscure task. In Exchange you can configure the AcceptMessagesOnlyFromDLMembers attribute which does what it sounds like it does: it only allows the mail recipient to accept messages from members of specific distribution lists. The problem is, there’s no built in method for appending a distribution list (DL) to an existing list of DLs. If you set AcceptMessagesOnlyFromDLMembers equal to a value, it overwrites what was there before. So, I wrote a quick script to append a value instead of overwriting it. You’ll need a remote Exchange Management Shell and the AD management module for this.

First things first, I declare the function named Add-AcceptMessagesOnlyFromDLMembers which is a bit more verbose than I’d usually like to make it, but I’m also a fan of descriptive function and cmdlet names.

Second, I need some parameters. The mail recipient whose AcceptMessagesOnlyFromDLMembers value we’re appending something to, and the DL that we’re appending.

Line 11 is where we begin doing the real work. I’ve got to get the mail contact and select just the value currently in AcceptMessagesOnlyFromDLMembers so I can append something to it. I store that data in $arr.

On line 12, I’m retrieving the CanonicalName attribute for the DL I want to append to the list of DLs that can send mail to this contact. The AcceptMessagesOnlyFromDLMembers attribute is a bit weird in that it only appears to take Canonical Names, not Distinguished names, etc.. I’m appending that value to the end of $arr.

Line 13 is pretty straight forward. I’m setting the AcceptMessagesOnlyFromDLMembers attribute to the value of $arr determined in line 12.

That’s it! If this is a task you perform regularly, please take this script and apply it. If you make it more robust, I’d love to see what your modifications are.


Getting Large Exchange Mailbox Folders With PowerShell

I’ve been continuing my quest to identify users who have large Exchange mailboxes. I wrote a function in my last post to find large Exchange mailboxes, but, I wanted to take this a step further and identify the large folders within user mailboxes that could stand to be cleaned out. For instance, maybe I want to find all the users who have a large Deleted Items folder or Sent Items or Calendar. You get the idea. It’s made to be run from a Remote Exchange Management Shell connection instead of by logging into an Exchange server via remote desktop and running such a shell manually. Remote administration is the future (just like my last post)!

So, let’s define the function and parameters.

My function is going to be named Get-LargeFolder and takes three parameters. $FolderScope is used in the Get-MailboxFolderStatistics cmdlet (spoiler alert) and must belong to the set of values specified. $Top is an integer used to define how many results we’re going to return and $Identity can be specified as an individual username to examine a specific mailbox, or left blank (defaulted to *) to examine the entire organization.

Now I’ve added a couple lines to get all the mailboxes in my organization (or a specific user’s mailbox) which I pipe into a Get-MailboxFolderStatistics command with the FolderScope parameter set to the same value we passed to our function. Now we need to sort the results, but, see my last post for why that’s going to be complicated.

The FolderSize parameter that comes back with a Get-MailboxFolderStatistics cmdlet is a string which I’m splitting up in order to get back only the value in bytes which I am casting to a double. Now that we have gathered our stats and put them in order, I just need to select them so they may be returned. Here is the complete script.

Now you can do this.



Getting Your Organizations Largest Exchange Mailboxes With PowerShell

In a quest to hunt down users with large mailboxes, I wrote the following PowerShell function. It’s made to be run from a Remote Exchange Management Shell connection instead of by logging into an Exchange server via remote desktop and running such a shell manually. Remote administration is the future!

My requirements were rather basic. I wanted a function that would return the top 25 (or another number of my choosing) Exchange mailboxes in my organization by total size. I also wanted the ability to specify an individual user’s mailbox to see how large the specific box is.

So, let’s get started.

All I’ve done here is declare my new function named Get-LargeMailbox and specified its parameters. $Top is the integer representing the number of mailboxes to return (defaulted to 1) and $Identity is the specific mailbox we want to return (defaulted to * which will return all mailboxes).

Now, I know I need to get my mailboxes and retrieve some statistics.

So far, so good. We haven’t narrowed down the stats we care about yet but we’re getting all the mailboxes in the organization and retrieving all the stats for them. Now we’re about to run into a problem. There’s a property returned by Get-MailboxStatistics called TotalItemSize but when you’re in a remote session, but, it’s hard to work with. Observe.

You can see it returns a property consisting of a boolean value for if my quota is unlimited, and then a value of what my total size is. Ok, so that value is probably a number, right?

Well, yeah, it is. The Value of TotalItemSize is a number but it’s a Deserialized.Microsoft.Exchange.Data.ByteQuantifiedSize and when you’re connected to a remote Exchange Management Shell, you don’t have that library loaded unless you install some tools on your workstation. Rather than do that, can’t we just fool around with it a bit and avoid installing a bunch of superfluous Exchange management tools? I bet we can, especially since this value has a ToString() method associated with it.

Back to our function. I need to sort the results of my “Get all the mailboxes, get all their stats” command by the total size of the mailboxes.

Oh boy, string manipulation is always fun, isn’t it? What I’ve done here is sorted my mailboxes by an expression. That expression is the result of converting the value of the TotalItemSize attribute to a string and manipulating it. I’m splitting it on the open bracket character, and then again on the space character. I’m taking the second last item in that array, stripping out the commas and casting it as a double (because some values are too big to be integers). That’s a lot of weird string manipulation for some of you to get your heads around, but look at the string returned by default. I need the number of bytes and that was the best way to get it.

Now all I need to do is select the properties from my sorted list of mailboxes and return the top number of results. Here’s the final function.

Now you can do things like this.

Before we end, let’s take a closer look at the last example.

First, I’m declaring an array to hold the results of users and how large their mailbox is. Then I’m getting all the members of a group, taking the SamAccountName and performing an action on each of them. That action, of course, is retrieving their mailbox size using the function I just wrote and appending the results to the array. Then I need to sort that array and display it. The Select-Object command has the formatting I included to make the mailbox sizes have commas separating every three digits.


Get All The Members Of The Distributions Lists That A User Is A Member Of

This is kind of a weird script tip but I bumped into a need for this kind of script so I thought I’d share it. In this post, I have a user and I want to get all the members of all the distribution lists that the user is a member of. That is to say, if the user is a member of DL1, DL2 and DL3 distribution lists, I want to get all the other members of all those distribution lists. You’re going to need a remote Exchange shell for this.

Here’s the code I came up with.

Line 1 is just declaring a variable to hold the DistinguishedName attribute for the user I am interested in. Line 2 is the work line. The first thing I’m doing is getting all the distribution groups which have a member equal to the DN of the user I’m interested in. Now, the weirdness happens…

When you do a Get-DistributionGroup, you do not get the members of that group back with it. Here are the properties that come back that contain the string “mem” in the name.

Nothing in there contains the members. So back to the command I wrote to accomplish my goal.

I’m piping the Distribution Groups returned into a Select-Object cmdlet to return the Name property and then a custom column. The label is Members and the content is going to just be a string of all the Distribution Group members’ names separated by semicolons. The expression for my custom column is a Get-DistributionGroupMember command for the Distribution Group piped into a Foreach-Object (alias is “%”) which returns an array of all the names of the members in the Distribution Group. I use the -join command to take the array and convert it into a string separated by semicolons.

It’s just that easy!


Detecting An Exchange Management Shell Connection

You don’t log onto an Exchange server via RDP and open the Exchange Management Shell application when you want to do Exchange-PowerShell things, do you? You follow the steps in my Opening A Remote Exchange Management Shell post, right?

But how do you detect if if you have an open remote connection or not? Well there’s a bunch of different ways so here’s an easy one. First, though, we need to understand a couple things about what happens when you open a remote Exchange Management Shell connection.

Here’s what the output of my Get-Module cmdlet looks like before I do anything Exchange-y.

Get-Module before anything Exchange related

Get-Module before anything Exchange related (click for larger)

I’m in ISE, I have the AD cmdlets added. Nothing going on here is too crazy. Now here’s what it looks like after I open a remote Exchange Management Shell connection like I told you how to do in the post linked above.

Get-Module after adding Exchange Management Shell

Get-Module after adding Exchange Management Shell (click for larger)

Notice that the Exchange stuff gets added under a tmp name? And that it’s different every time? That doesn’t exactly make it easy to detect. With the ActiveDirectory cmdlets you can just run Get-Module -name ActiveDirectory and it will either return something or not. Easy. How are you supposed to do that in a predictable, repeatable fashion for Exchange, especially since any other remote shells created to other services in the same manner may also be added with a tmp_ prefix?

In order to figure out how we can determine if we have a module added that belongs to a remote Exchange Management Shell, let’s take a closer look at the tmp module that just got added.

Details of the last module added

Details of the last module added (click for larger)

At first glance, we’re obviously not going to be able to use the Name or Path attributes to identify remote Exchange Management Shell connections. ModuleType, Version, most of the others all look useless for us here. What looks useful, though, is the Description attribute which reads “Implicit remoting for http://my-exchange-server.fqdn/powershell”. That, we can work with. Here’s my code to tell me if I have a module added whose description is for a remote session to my Exchange server.

The code will either return the description of the module if it’s added, or null. You can work with it like this.

Check it out.

Code at work

Code at work (click for larger)


Quick Tip: Searching Exchange Message Tracking Logs (Get Results From Every Server)

When you use the Get-MessageTrackingLog cmdlet, by default, it only searches for messages/events on the server that you’re connected to (see my post on creating connections to Exchange). That’s not great in a multi-server environment. I want results from every server.

My solution is the following.

The Get-TransportService cmdlet gets a list of all the transport servers in your infrastructure. For each of the servers we get back, I’m running the Get-MessageTrackingLog cmdlet and appending the results to a $results variable. I’m taking that results collection and sorting it chronologically.


Quick Tip: Find All The Mail Enabled Groups A User Is A Member Of

Here’s a one-liner that will help you find all the mail enabled groups that a user is a member of. A little pre-requisite reading is this bit on group types to understand the difference between a security group and a distribution group: https://technet.microsoft.com/en-us/library/cc781446%28WS.10%29.aspx?f=255&MSPPError=-2147217396

Here’s the one-liner!

It might not be the epitome of efficiency but it works and served me well when I needed it to.

First, we’re running a Get-ADUser command on our interesting user and making sure to retrieve the MemberOf property in addition to the standard properties returned. Out of all of the returned properties, it turns out that MemberOf is the only one I’m interested in so I select only that property by wrapping the command in brackets and appending .MemberOf. Second, I’m piping all of the groups that the user is a member of into a foreach-object loop. For each of the objects returned, I’m performing a Get-ADGroup. I have to do this because I can’t necessarily tell which groups the user is a member of are mail enabled just from their name, I have to run the Get-ADGroup command to get more information. I’m piping these results into a where-object command where I select only the groups whose GroupCategory is equal to “Distribution” (see the pre-requisite reading above). Then I format the group names into a table.

I could have got every group in my Active Directory and searched for groups that contained my user as a member and were Distribution types, but in my situation, it was faster to only spot check the groups that the user was actually a member of. I have a lot of groups, you might not.


Imported PowerShell Sessions ErrorActionPreference Gotcha

I just bumped into something silly that I know I’ll forget about in the future. Using the function in my PowerShell profile to open an Exchange Management shell, I ran the following command as part of a script.

It’s a pretty self-explanatory command. I was trying to detect if a mailbox, in this case “doesntexist”, existed or not. Typically if the mailbox doesn’t exist, the Get-Recipient cmdlet will throw an error. My goal was to catch the error and do something productive with it but the above command doesn’t trigger the Catch block.

No problem, I thought to myself. My ErrorActionPreference is set to Continue by default so I’ll tweak it for this command.

The -ErrorAction Stop part should make the script stop executing on an error and hop into the Catch block. Wrong! The above command throws an error without triggering the Catch block, too.

It turns out I had to edit my $ErrorActionPreference variable to be Stop. Just using the flag in the command doesn’t work. I’ve run into this in other scripts where I import a PSSession, too. Now my command looks something like this.

First, I’m getting the current value of $ErrorActionPreference and storing it. Then I set the ErrorActionPreference to Stop. I run my Get-Recipient command which fails and now instead of getting an error, my Catch block is triggered. Afterwards, I set $ErrorActionPreference back to it’s previous value.

Now, because I’ve written a blog post about this, I’ll never forget again.


Quick Tip: When was an Exchange Online Protection Transport Rule Changed?

What if you have an Exchange Online Protection (EOP) transport rule that isn’t behaving the way you thought it should? I’ve been the victim of some strange inconsistencies with EOP since they tried to migrate us from Forefront Online Protection for Exchange (FOPE) in March (actually summer) of last year.

So did a transport rule get changed administratively by some cowboy admin colleague? Or is EOP conspiring against you? In EOP’s GUI, you can’t tell when a transport rule was changed last but you can if you make a remote connection to EOP using PowerShell.

You just need to know the name which you can find by running a Get-TransportRule command and looking for the one that you’re interested in. Then run this…

… which will give you the date and time that the rule was last changed.