Wednesday, October 31, 2012

Auditing Full Access Permissions

One of the nice things about Exchange Management Console (EMC) is how easy it is to grant Full Access permissions. One of the bad things about EMC is also how easy it is to grant Full Access permissions! For troubleshooting purposes or through the course of creating resource/shared mailboxes, it is often necessary to do just that - for example, it can be helpful for an admin to be able to get in to a mailbox for resetting permissions, or it can be most useful for a user (or users) to manage a resource mailbox instead of granting a lot of granular permissions. Well, because of how easy it is, it can be easy to lose track of those mailboxes to which your admin account has been granted access. Or maybe an admin is leaving and it is necessary to determine which mailboxes they granted their own account or their admin account access to to make sure no permissions remain that shouldn't. The question that I had was how to get this information - how to determine (without checking every mailbox manually via EMC) what mailboxes a specific user account had been granted Full Access to.

While researching this issue and how to get this information, I came across a lot of great sites with great information and ideas. I picked out a couple of common threads which I was able to put to use in our environment. First is Get-Mailbox, and second is Get-MailboxPermission. As mentioned above, I basically want to query all of the mailboxes for instances in which a known, specific account has been granted explicit Full Access permissions. Below is what I came up with:

Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission -User [USERNAME] | where{$_.IsInherited -eq $false} | fl Identity,User,AccessRights

To break this down piece by piece, here are the different elements:

  • ResultSize: this is set to "Unlimited" because we have over 1,000 mailboxes and I want to query all of them
  • User: here is where I am entering the name of my administrative account (or the name of any other user who may have rights) - the brackets are not part of the actual input
  • where{$_.IsInherited -eq $false}: This is the piece that will tell me if the account has been given explicit permissions via EMC - which reminds me, if you haven't become familiar with it already, make sure to read up on the "$_." trick
  • fl: (a.k.a., format-list) I found these three pieces of information to be the most useful; I can see the mailbox to which permissions have been granted, I can confirm it's the user I'm checking for, and I can see if it is truly Full Access or some other combination of permissions
This can be a handy way to do some quick administrative access auditing, and hopefully this script has been helpful. As always, feel free to leave some feedback with any questions/comments!

Friday, October 12, 2012

Auditing Allowed Relays

Today's post will be a brief discussion of how to audit the systems that have been granted permissions to relay through Exchange (Exchange Management Shell > Server Configuration > Hub Transport > Relay Connector properties > Network tab > "Receive mail from remote servers..."). If your organization is like mine, you may have a pretty lengthy list of IP addresses that have been granted access (we have over 100 entries), and you may need to perform periodic audits to make sure you have a good handle on exactly what systems have the ability to send through your Exchange environment. My original research into this topic led me here, and I adapted what I found for use in our environment and made sure to understand what I was reading.

The basic process is to run an Exchange Management Shell (EMS) command to extract the desired information from Exchange, clean up the output, and then use a utility (and detective work) to figure out what hosts are behind the IP addresses. I will present the EMS command (which will probably work without any changes), but I will also go into detail about the how and why - and as always, I welcome any feedback that might help me improve on my methods.

(Get-ReceiveConnector "Relay Connector").RemoteIPRanges | fl LowerBound > C:\Temp\RelayList.txt

Piece by piece, here is what you are seeing:
  • Get-ReceiveConnector: This will help you to get the name of your relay connector (which for us is "Relay Connector" - go figure!)
  • RemoteIPRanges: If you perform the part of the command above in the parenthesis and add "| fl" (pipe symbol followed by "fl"), you'll get the data stored within the Relay Connector, and you'll see that the IP addresses that have been granted access are stored in the RemoteIPRanges value - unfortunately, the list may be too long for EMS to show in this simple output
  • LowerBound: If you continue with connecting the dots, the output of the command leading up to the "|" (pipe symbol) will give you detail regarding the IPs in the relay list - but now we have the problem of too much information. Unless you actually granted access to a range (we did not), you just need either the LowerBound IP or the UpperBound IP (which should match since access has been granted on a per-IP basis). Pick whichever value (or both?) works for you.
Ultimately, the EMS command above gets you a text file with the list of IP addresses that have relay access, but as I mentioned, you'll need to clean up the text file by removing  all of the excess blank lines and the "LowerBound : " at the beginning of every line (Notepad++, anyone? See my previous post for further detail regarding using Notepad++ to do some of this cleanup). Now that you have a list of nothing but IP addresses, this list can be plugged into FastResolver (or your IP resolution software of choice) to get the hostnames of the systems. You will likely get several results that don't resolve, so work with your network team or do your detective work to determine what these systems are.

Finally, with all of this useful data in hand, create yourself a spreadsheet or other document to keep track of this information, and for extra credit, be good about keeping the information up to date!

Friday, October 5, 2012

Setting User Account Expiration Time

I recently handled a ticket which prompted me to revisit using the "Account expires" field in Active Directory Users and Computers (or the "accountExpires" attribute). In this ticket, it was indicated that it was very important that a user account be disabled at a specific time. I researched how the expiration field works, and found that if this flag is set, the default behavior is to expire the account at the very end of the chosen day as the clock is ready to roll over to midnight. Clearly, this wouldn't suit the requirements of expiring the account at end of business (or at any other time of the day), and I don't want to take the chance of forgetting to do it manually at the specified time.

While researching how to handle this, I came across some articles that pointed me towards a TechNet page that discusses the Set-ADUser command in the Active Directory Module for PowerShell. It turns out there's a parameter called "AccountExpirationDate" that does exactly what we need! I would recommend reading the parameter details because of how flexible it is regarding the time/date syntax it will accept, but the following command did the job for me on this particular account:

Set-ADUser -Identity [USERNAME] -AccountExpirationDate "10/05/2012 5:00:00 PM"

I'm sure I will be using this command plenty more in the future, and I hope you have found this information helpful!

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!