Exchange 2013 Powershell Script: Get DAG-wide Mailbox Statistics

While preparing for our On-prem -> O365 migration of a subset of our users, we ran across the need to gather mailbox statistics so that we could create the migration batches based on metrics.

It’s pretty simple for us to do so as the subset of users were housed on one of our DAGs, so all we needed to do was query all of the servers for all of the mailboxes, get the stats, package them up, and dump it to a CSV in a meaningful format so that we could use it both for the scoring and analysis scripts.

This script needs little preparation to run in your environment – you could actually run it against all dags with a bit of work, but I was focused on just 1 for my migration.

Modify the “$DagName” variable with your exact DAG name, save it, and run it. It will take a while to run since it’s enumerating all mailboxes and gathering data, and for larger organizations it will be a bit of a memory hog as it’s creating an array of objects in memory for its duration before it dumps them out to CSV.

$DagName = "DAG01"
$DateTime = Get-Date
$FormattedDateTime = $DateTime.Year.ToString() + "." + $DateTime.Month.ToString() + "." + $DateTime.Day.ToString() + "." + $DateTime.Hour.ToString() + "." + $DateTime.Minute.ToString() + "." + $DateTime.Second
$OutputFile = ".\$($DagName)MailboxStats-" + $FormattedDateTime + ".csv"

$Results = @()
$DAG = Get-DatabaseAvailabilityGroup $DagName -Status

foreach($Server in $DAG.StartedMailboxServers)
    $Mailboxes = get-mailbox -Server $Server -ResultSize unlimited

    foreach($Mailbox in $Mailboxes)
        $Statistics = get-mailboxstatistics $Mailbox
        $output = New-Object PSObject
        # Add members to the PSObject
        $output | Add-Member -type NoteProperty -name Name -value $($
        $output | Add-Member -type NoteProperty -name SamAccountName -value $($Mailbox.samaccountname)
        $output | Add-Member -type NoteProperty -name UserPrincipalName -value $($Mailbox.UserPrincipalName)
        $output | Add-Member -type NoteProperty -name DN -value $($Mailbox.distinguishedname)
        $output | Add-Member -type NoteProperty -name OrganizationalUnit -value $($Mailbox.OrganizationalUnit)
        $output | Add-Member -type NoteProperty -name CustomAttribute1 -value $($Mailbox.CustomAttribute1)
        $output | Add-Member -type NoteProperty -name ItemCount -value $($Statistics.ItemCount)
        $output | Add-Member -type NoteProperty -name DeletedItemCount -value $($Statistics.DeletedItemCount)
        $output | Add-Member -type NoteProperty -name AssociatedItemCount -value $($Statistics.AssociatedItemCount)
        $output | Add-Member -type NoteProperty -name TotalItemSize -value $($Statistics.TotalItemSize -replace "(.*\()|,| [a-z]*\)", "")
        $output | Add-Member -type NoteProperty -name TotalDeletedItemSize -value $($Statistics.TotalDeletedItemSize -replace "(.*\()|,| [a-z]*\)", "")
        # Add the output object to the master Results object, which is returned on script completion
        $Results += $output

$Results | Export-Csv -Path $OutputFile -NoTypeInformation

You will need to be in an Exchange 2013 prompt to run this, and have the requisite permissions in the Exchange org to access the stats.

Posted in Exchange 2013, Management, Powershell | Tagged , , , | Leave a comment

Exchange 2013 Powershell Script: Get System Wide Message Queue Status

Ran into a case where we had some delivery issues to our O365 hybrid tenant, and realized I’d never figured out a good way to take a look at all of the queues at once, and lets face it, the Exchange Toolbox Queue Viewer tool is just…sad at this point. I mean it works, but I want to know what the entire environment is doing at a glance and what our message velocity looks like. This is where the following quick script comes into play.

It’s designed to be run out of an already-connected Exchange 2013 powershell prompt, so connect using your usual method or go take a look at Chris Lehr’s blog for an awesome tool to manage your connectivity needs.

When you run it, you’ll get a screen that constantly refreshes (so you can toss it into 1 window/corner of your monitor and just let it run) and it will look similar to this:


It’s pretty simple and straight forward at this time. I have it saved as “get-messagequeuestatus.ps1” in my network script repository for use from any machine.

    Get-ExchangeServer | Get-Queue | where {$_.MessageCount -gt 0} | sort MessageCount -Descending | ft -a
    sleep 10

I may make some enhancements in the future for color coding, requesting a certain refresh rate, etc. but for now, it’s quick and dirty and works.

Posted in Exchange 2013, Management, Monitoring, O365, Powershell, Uncategorized | Tagged , , , , , | Leave a comment

DPM 2012 R2 Search Recovery Point Action Failing to Produce Results

Recently I’ve had to switch from Backup Exec 2014 to Microsofts System Center Data Protection Manager 2012 R2 to handle our Exchange 2013 CU5 backups due the Backup Exec 2014 not supporting the Exchange 2013 SP1 + Server 2012 R2 feature of clusters without Cluster Administrative Access Points.

This went swimmingly, besides a problem with Exchange 2007 and Exchange 2013 CU5 not being able to be scanned by the 2013 CU5 ESE*.* files, until we attempted to test restores.

At the restore point, I could browse through the trees, but trying to search the recovery points for specific Exchange mailboxes failed.  Totally failed.  No response whatsoever failed.  Pulled out NetMon and looked at traffic and didn’t see the query going to the SQL server failed.

A brief call to Premier support later, and a gentleman quickly gave me the solution as he’d seen it once before:

By default, a limit of 100 connections to the SQL database is allowed, and this needed to be increased in our case.

To do so, in RegEdit, go to HKLM\SOFTWARE\Microsoft\Microsoft Data Protection Manager\DB, and append the following string:

;Max Pool Size=400

To the following 2 keys:


You should end up having a connection string like so:

Integrated Security=SSPI;Initial Catalog=DPMDB_DPMServerName;Application Name=MSDPM;server=tcp:ServerIPAddr;Connect Timeout=90;Max Pool Size=400

After doing so, close any DPM Administrator Consoles you may have open, then restart the MSDPM and DPMAMService services, reopen the administrator console, and try your search again.

Posted in Disaster Recovery, DPM 2012 R2, Exchange, Exchange 2013, Installation | Tagged | Leave a comment

Exchange 2013 SP1 Fun: Identity Management Systems Are…Good?

Long time no blog, I know.  I’ve got a dozen or so posts racked up from when I thought I was going to transition the blog over to Office 365 and my SharePoint installation there, but the setup just isn’t conducive to blogging without a lot of work.  And let’s face it, ain’t no one got time for that.  Or at least I won’t for another year or so.

So here we are.

I’m going through an Exchange 2007 to Exchange 2013 SP1 migration…which is now turning into an Exchange 2007 to Exchange 2013 CU5 migration thanks to an issue with our environment.  We’ve been rocking SP1 in all of the testing – greenfield lab installs, test lab installs with production data copies, etc.  All were rocking along (minus a SYSVOL issue in both the test lab and production), until the production install came along, and our in-house Identity Management system decided that it would find the new OU created by Exchange 2013 Sp1 (“domain\Microsoft Exchange System Objects\Monitoring Mailboxes”) and promptly delete the user objects under it as it didn’t recognize them.

Custom Identity Manager deleted them :(

Exchange created these.

So yeah.  Exchange 2013 SP1 doesn’t like that, not one bit.  About 15 hours total with 6 spent with Microsoft Premier support, and it was determined that:

  1. Exchange 2013 doesn’t like when you delete those mailboxes.
  2. We were also seeing a bug that was fixed in CU5 with health monitors not resolving themselves among other issues.
  3. Wiping and reloading the server (after uninstalling Exchange 2013 from it!) is the best bet to fix it.

Now, I typically let the rest of the user community go through and find issues with CU-esque updates, but we’re looking at a fresh install in separate AD sites, a flexible cutover to production, and an understanding management team.

However, after rebuilding the nodes on CU5, they have come up clean, so this does appear to be the way to go!

Posted in Active Directory, Exchange 2013, Installation | Leave a comment

HP 3Par Array Management: LDAP Authentication

I’ve been administering 3Par arrays for the past 5 years for my organization, and only recently have we bothered with LDAP authentication.  We are running 3.1.1 MU2 on our primary array, and wanted to start bringing in additional administrators to lighten my workload, so LDAP seemed the best way.

Typically I perform most tasks from the GUI, however for LDAP configuration, save yourself a headache and go to the CLI.  The GUI has problems with some of the fields (such as being obvious about what data they want entered), and the CLI just makes more sense once you start looking at the requirements.

The nice thing about this particular implementation of LDAP is that it’s relatively AD aware, but not what I would call optimal.  Optimal would be specifying the domain, and having the system pull in the domain controller and kerberos server information for you.

Instead, we have to specify a particular domain controller (which leaves you open to failing to authenticate during patching/reboot cycles – hope you don’t mind) and the specific kerberos server (same problems).

I see this a lot with non-MS products (and poorly written .Net products).  I wish someone, somewhere would tell these guys that their coding laziness is pathetic.  You know, like I just did.  Hint, hint.

Anyhow, on to the settings and commands.

Notable commands:

  • showauthparam – Used to display the current content of your authentication parameters.  If none are set, this will show up empty.
  • setauthparam – Used in conjunction with a parameter name and a value, which will set the parameter.
  • checkpassword – Used to test out credentials.  Keep in mind the system will check locally for the user and then check LDAP credentials, so if you’re trying to use an account named the same locally as well as in LDAP, then it will fail out if you’re not using the local password.  It does NOT attempt to authenticate against LDAP if it fails locally.


The following are examples of commands that will produce a configuration that worked in my environment.  I run a relatively flat environment with a decent amount of domain controllers, however as it’s not fully AD-aware, it’s going to be pointed towards 1 domain controller.  I’ve cleansed the data, but it should all make sense shortly.

Parameters and example data.

Parameters and example data.

You can see that the parameters ending in “attr” are actually the AD attributes that contain the data that the authentication mechanism is looking for when it performs its queries.  Kerberos realm MUST be in all caps.  Note that the “super-map” value (the DN of the admin group) has no spaces; if your DN includes spaces, enclose the DN in double quotes to insure that it maps properly.

Running those commands on the CLI (adjusted for your environment) will yield a configuration that will allow for checking a username, as shown below:


Though it’s heavily redacted, you can get the gist of the process that it goes through to connect and validate that the user is a member of the appropriate group.  I first displayed the parameter values using showauthparam, then I tested the configuration using checkpassword.

Once this is complete and comes back clean, you’re on your way to logging on with your domain credentials.  And hopefully HP/3Par will one day build in the ability to enable pass-through authentication similar to how the VMWare vSphere Client functions.

Posted in Management, Storage | Tagged , , , | 1 Comment

Exchange 2013 Sizing Guidance Available (Finally!)

I expected this to be released about 2 months ago, but it turns out they were biding their time for IronMan 3 to drop so we’d all be a bit too distracted to notice that they’ve put together a great post on the Exchange Team Blog about sizing 2013.

What they still have NOT done, however, is finished up the sizing calculator.  It looks like they’re working on it, but that is still a while away.

Head on over to their latest entry, Ask the Perf Guy: Sizing Exchange 2013 Deployments, to find out more.

Once I’ve had a chance to parse through a bit more I’ll toss a gist out there.

Posted in Exchange 2013 | Tagged , , , , , | Leave a comment

Powershell Code: How to Extend Password Age in Active Directory

We have a subset of users whose passwords are not expired while they are in a certain stage of their existence.  We store these accounts in 1 particular OU, and once they are ready to move on to their next stage of evolution, we expect them to learn how to change their passwords.

In the past, we’ve utilized a VB script to update the ‘pwdLastSet’ field on the account, but as the number of users matching the parameters for this stage has increased, the amount of time that it takes this script to function has risen dramatically.

So, I took some time to go ahead and rewrite it in Powershell as it is simple enough to not need a C# executable.

I’ve run it through performance testing, and it’s a massive increase in performance.  On average (in my testing), for every hour of the old code running, you’re left with 1 minute worth of new code processing time.

## Requires Server 2008 R2 or later

## Import the Active Directory Powershell module
Import-Module ActiveDirectory

## Path to the applicants OU
$ADsPath = [ADSI]“LDAP://OU=TestOU,DC=Domain,DC=Local”

## Create the directory search object to the find the matching objects
$Search = New-Object DirectoryServices.DirectorySearcher($ADsPath)

## Filter translates to "Any user account that is not disabled"
$Search.filter = “(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))”

## Required to exceed 1000 records automatically
$Search.PageSize = 1000

## Limits the search to the specified OU
$Search.SearchScope = “OneLevel”

## Perform the search and return the records into the array $results
$results = $Search.Findall()

## Loop through the array to process the changes
Foreach($result in $results)
 ## Get the directory entry
 $User = $result.GetDirectoryEntry()

 ## Get the accounts samAccountName
 $name = [string]$User.samAccountName

## Produce an ADUser object to represent the account with only the properties needed
 $adoUser = Get-ADUser $name -Properties pwdLastSet

## Perform the first reset - 0 sets the account to require the password be changed
 $adoUser.pwdLastSet = 0
 Set-ADUser -Instance $adoUser

## Perform the second reset - 1 actually sets the pwdLastSet value to automatically enter the current datetime value
 $adoUser.pwdLastSet = -1
 Set-ADUser -Instance $adoUser


As usual, make sure that you know what you’re doing, and test this out on a test domain first with a few test objects. I am not responsible if you hose everything under the sun.

Posted in Active Directory, Management, Powershell | Tagged , , | Leave a comment