Friday, September 28, 2012

Exporting a Mailbox To a PST File

Today's discussion is going to be regarding exporting the contents of a mailbox (or a specific folder or folders) to a PST file. While this is a pretty simple task, I would like to share a couple of my tricks and some things I have picked up along the way.

It all begins with the New-MailboxExportRequest command. As shown in the TechNet article, you only have to provide two parameters to the command to get it to work: a FilePath to store the resulting PST and the Mailbox to perform the action on. At its most basic, when I receive a generic mailbox export request, I run the following in Exchange Management Shell (EMS):

New-MailboxExportRequest -Mailbox [ALIAS] -FilePath "\\[EXCHANGE-SERVER]\X$\PSTs\[ALIAS].pst"

I like to use the "Alias" (rather than SMTP Address or Display Name) simply because it is usually the easiest to enter. I then use that same Alias as the name of the PST file to make it easy to identify. For the FilePath, I have some space set aside on one of our mailbox servers that I use to temporarily store the file in. Why one of the Exchange servers? Well, as I discovered through trial-and-error, and ultimately as shown in the TechNet article, "You need to grant read/write permission to the group Exchange Trusted Subsystem to the network share where you'll export or import mailboxes. If you don't grant this permission, you'll receive an error message stating that Exchange is unable to establish a connection to the target mailbox." These permissions are already in place on the Exchange servers, so I didn't have to fiddle around with extra permissions on any of our typical file shares - I simply move the PST file from the Exchange server to a location accessible by the user that requested the file.

One of the first tricks I learned with this command was a result of a MailboxExportRequest terminating with a "Failed" status. This is usually a result of bad items in the mailbox; consequently, run your command once more with the addition of the "BadItemLimit" parameter. The EMS command would then look like this:

New-MailboxExportRequest -Mailbox [ALIAS] -FilePath "\\[EXCHANGE-SERVER]\X$\PSTs\[ALIAS].pst" -BadItemLimit 25

I just randomly picked a BadItemLimit of 25, and have had pretty good luck with it. If your command still fails, you can increase your limit (NOTE: going over 50 introduces some new complications, so refer to the TechNet article for additional information).

The game changes a little bit for export requests resulting from discovery requests. As a quick overview, a discovery request  is carried out via Exchange Control Panel (ECP) and the discovered items are copied to a sub-folder of a special mailbox dedicated to discoveries. In this case, you may have one Discovery mailbox, but there may be multiple discovery results in the mailbox. To limit the items that get exported, we'll use the "IncludeFolders" parameter:

New-MailboxExportRequest -Mailbox "Discovery Search Mailbox" -IncludeFolders "[DiscoveryName]/*" -FilePath "\\[EXCHANGE-SERVER]\X$\Discoveries\[DiscoveryName].pst"

You'll need to update the name of your Discovery mailbox for the "Mailbox" parameter (the quotation marks are due to the spaces). In our organization, the discovery would be requested in a ticket, so I like to use the ticket number for the folder to store the data in during the discovery, and then as the name of the PST file for the export request.

Finally, don't forget to clean up when you're done! As discussed at the beginning of the TechNet article, Exchange will automatically generate a unique name for the export request when performed as discussed above, but it will only work the first 10 times. After the first 10, you have to begin naming your export requests. The easiest command I have seen for clearing completed export requests is the following:

Get-MailboxExportRequest -Status Completed | Remove-MailboxExportRequest

Happy exporting, and feel free to let me know if you have any tips or tricks of your own!

Friday, September 21, 2012

DAGs and Database Distribution

The organization I work for is pretty large - we have several thousand users with between half and two-thirds having mailboxes, and we have a multi-server Exchange environment with a DAG and separation of roles. Due to the nature of our organization, we have several dozen databases (which might end up being another interesting topic of discussion: how big are you comfortable letting your database get before restores get cumbersome? what prompts splitting them? what is your logic regarding sorting your mailboxes into databases?). When I started working here, there were two servers in the DAG. Things were pretty easy to configure in terms of where to put the active/passive copies. We'd either have 100% active on one server and 100% passive on the other, or we'd do a 50/50 split on both servers. Due to performance issues, we introduced a third member of the DAG, and it was at this point that I began researching best practices for how to distribute active and passive copies of the databases. Here are some of the tips, tricks, and helpful information I picked up as I worked through this puzzle.

The first thing you'll want to do is get a listing of your mailbox databases. Since right now all we care about is the names of the databases, let's use the following in Exchange Management Shell (EMS):

Get-MailboxDatabase | fl Name > C:\Temp\Databases.txt

While this will give you a list of just the names, there will be some cleanup to do in the resulting text file before copying and pasting the list into your spreadsheet program of choice for the rest of the work. If you don't already use it, I highly recommend Notepad++ with the "TextFX Characters" plugin installed for just about anything text related. The bottom line is that you're going to need to remove all of the "Name : " text at the beginning of each line (using Find/Replace), and then remove all of the blank lines (using TextFX > TextFX Edit > Delete Blank Lines). The resulting list can now be cleanly copied and pasted into your spreadsheet program.

The rest of what I'll be discussing comes from information I gathered from The Exchange Team Blog and TechNet. Both of these articles focus on a DAG with four members, so the fun part for you will be adapting the information to your environment. I can't emphasize this enough: follow the two links above, understand the logic behind the distribution, and adapt it to your environment. I am including a table that I find useful for our environment to illustrate the solution I worked out for our three member DAG in which each active database has two passive copies. After making my spreadsheet, I noticed that the same pattern was repeated in a block, so it became a simple matter to finish my spreadsheet simply by copying and pasting the block through to the end of my list of databases.


Server1 Server2 Server3
Database1 Active Passive1 Passive2
Database2 Passive2 Active Passive1
Database3 Passive1 Passive2 Active
Database4 Active Passive2 Passive1
Database5 Passive1 Active Passive2
Database6 Passive2 Passive1 Active

If you think of Database1 - Database6 as a block, this pattern will repeat for 7 - 12, 13 - 18, etc. So, copy and paste away! From here, you will go to Exchange Management Console (EMC), and you will alter the properties of the Database Copies to change the activation preference to match the configuration in your spreadsheet.

The final step of this project is to actually redistribute your databases to apply the changes you outlined in your spreadsheet and your activation preferences. If your environment is like ours, this could be a large, cumbersome project. Fortunately, I came across a script that takes care of redistributing the databases to be consistent with their activation preferences. The best part about it is that you already have the script - it is on your Exchange servers in a folder called "Scripts" in the Exchange installation directory. The script is called "RedistributeActiveDatabases.ps1", and I will go into some detail about the two most useful ways I have found to use it.

If you enter the following into EMS, it will present you with a table that shows you your current database distribution. This is a neat tool because it presents you with an at-a-glance view with side-by-side numbers that will show you the total number of databases (including database copies), how many are active, how many are passive, and a "Preference Count List" that will show you a break-down of the activation preferences. The script must be run from a mailbox server, and since it's informational, there are no concerns about affecting your production environment:

.\RedistributeActiveDatabases.ps1 -ShowDatabaseDistributionByServer | Format-Table

The following usage of the script is the one that actually does the heavy lifting - do not run this script in your production environment without following your organization's change control process! The script will go through your databases and switch them over based on the activation preferences that you configured after working through your spreadsheet. Typical usage of this script for me comes after running Windows Updates on my Exchange servers. I'll switchover Server1 to Server2 to get the databases off of the first server to update, and then I'll typically switchover Server2 and Server3 back to Server1 to finish updating my other two servers. This leaves me with 100% of my active databases on Server1. Running the following version of the script will sort everything back out:

.\RedistributeActiveDatabases.ps1 -BalanceDbsByActivationPreference -Confirm:$False

Taking the time to work out our database distribution and using the script to help audit and manage the databases has been very helpful, and we have certainly noticed a positive impact on our Exchange environment.

Friday, September 14, 2012

Updating Active Directory User Attributes via PowerShell

One of the issues I have encountered is how to update an attribute for multiple user accounts when the attribute is not one of what Microsoft refers to as a "commonly used property value". For example, we use an attribute called "employeeType" to store an employee's Organization Code. This is not an attribute that you'd see if you select multiple accounts and view the Properties. So, how do you update the attribute? Well, in researching the issue, I came across this site, and I was able to use it as a springboard to get to a solution that fit my needs. The missing piece for me was that the Get- and Set- commands don't know what to do with the uncommon property value, but looking into the command usage via TechNet got me the rest of the way to a solution. As you will see with most of my scripts, I like to use a CSV file as my input for the scripts since it is common for me to update anywhere from a few to dozens (if not hundreds) of accounts at one time.


#################################
# Script to update attributes for Active Directory users
#
# Script by SLCSysAdmin - please credit and link!
# http://slcsysadmin.blogspot.com
#
# NOTE: be sure that "Active Directory Module for Windows PowerShell" 
# is loaded in PowerShell before running
#################################

$dataSource=import-csv "AccountList.csv"
foreach($dataRecord in $datasource) {
$sAMAccountName=$dataRecord.sAMAccountName

# List of attributes to update
$employeeType=$dataRecord.employeeType
$department=$dataRecord.department

# NOTE: For the following item, the extra code is necessary because "employeeType" is not 
# one of the "commonly used property values" as found in the following list:
# http://technet.microsoft.com/en-us/library/ee617215.aspx
Get-ADUser -Identity $sAMAccountName -Properties employeeType | Set-ADUser -Replace @{employeeType=$employeeType}

# NOTE: The following is much simpler because "department" is one of the common property values
Get-ADUser -Identity $sAMAccountName | Set-ADUser -Department $department
}

It is worth mentioning for first-timers that your column names in your CSV file need to match what you're doing in your script. For example, my CSV file would look like this for use with the code above:

sAMAccountName,employeeType,department
usernameA,1234,IS
usernameB,9876,BB
...
usernameZ,3476,ZZ

When the request comes in to update different attributes, make the necessary changes to the script and make sure you update your columns in your CSV file accordingly. Enjoy, and feel free to hit me with your comments or suggestions!