Wednesday, April 13, 2011

Restore Active Directory Account and Mailbox using Exchange Database

In this article, I have explained the various steps involved in re-producing the subject issue.

Before you begin To perform the following procedures, the account must be delegated the following:

Exchange Organization Administrator Role

Though this article was already present in TechNet site, I have tried to make it easier to understand with some screenshots.

Now in the previous versions of exchange it was quite easy to restore the backup to recovery server (EXCHANGE 2000) or by creating RSG (EXCHANGE SERVER 2003). In Exchange server 2007 the process is different. I am going to show you how this can be accomplished by using Exchange Management Shell.

For testing purpose I had created few accounts. And will be deleting those accounts after taking backup.


Now an administrator has three options in Exchange Server 2007 for deleting an AD account.
Either we can use EMC, EMS or Active Directory Users & Computers.
Below is an example using EMS? Here we are deleting RAM.


Below is an example using EMC? Here we are deleting SAM account; however the mailbox will show in the disconnected mailbox. The user will lose all AD related permission.


Be careful while selecting the Remove option.


Below is an example using ADUC? Here we are deleting TAM. The mailbox will show in the Disconnected Mailbox.


Now since I have a backup I can either restore data directly to the production, doing so will lead to downtime & there will be an inconsistencies for end users (Not recommended).
The best option is to create Recovery Storage Group.
In this example I had already created RSG. If you have trouble creating RSG please refer to TechNet site.
Click here.

Since Exchange Server 2007 has the capability of mounting database on any server within the same ORG.

In this example I had created RSG & moved the database to a newly created Mailbox Store. New Database was created since we don’t have an option of getting Mailbox Statistics using Exchange Management Shell for RSG. Once the database is restored to RSG check the database health and then copy it to the Production Store (Temporary).
Make sure you rename the database file.
For example in our case the database file name was Mailbox Database.edb. I had renamed it to Mailbox Databases.edb.


Remember you have to paste this .ps1 file in the below location. In below ....

C:\Program Files\Microsoft\Exchange Server\Scripts

Run the below command to create .ldf file.
Here I had created an OU named “DisasterRecovery”. Customer might have OU’s so simply provide the DN of the OU and the command will export all disconnected mailboxes and associated user account to file named as “ldifout.ldf”.
Note: – The user accounts are still not created.



In the above notepad I had removed all other accounts and I just kept only those accounts for which we are working. (RAM, SAM & TAM).


In the above command it says only 3 entries modified. This is because I had modified the .ldf file. Once the above command completes successfully you can see the account and mailbox created.



Since we had created this users and mailboxes using Exchange Management Shell. You have to restart IIS & MsExchangeIS service. Further you have to make sure UPN for these users is showing up in the Active Directory Users & Computers if not add them manually.


Now you can see SAM is able to login and able to see his old emails.

Make a note of this Technet article to help with downloading scripts: http://technet.microsoft.com/en-us/library/bb430758(EXCHG.80).aspx

CreateLdifFromDisconnectedMailboxes.ps1 (Save in to PS1)

Param(
[string] $ContainerDN,
[string] $Database = "",
[bool] $append = $false
)

#function to validate input parameters
function ValidateParams
{
$validInputs = $true
$errorString = ""

if ($ContainerDN -eq "")
{
$validInputs = $false
$errorString += "`nMissing Parameter: The -ContainerDN parameter is required. Please pass in a valid container in which to create the user accounts."
}

if (!$ContainerDN.Contains(","))
{
$validInputs = $false
$errorString += "`nInvalid Container DN. Make sure to enclose the entire DN in double quotes or it will not be parsed properly."
}

if (!$validInputs)
{
Write-error "$errorString"
}

return $validInputs
}

#function to get the display name and alias from mailbox data in the Exchange store
function ExtractDisplayNameAndAlias($obj)
{
[string[]]$legacyDNSplit = $obj.LegacyDN.Split('/')
$alias = $legacyDNSplit[$legacyDNSplit.Length-1].Remove(0,3).ToLower()
$output = "dn: CN=" + $obj.DisplayName + "," + $ContainerDN + "`r`nchangetype: add`r`nuserAccountControl: 544`r`nmsExchUserAccountControl: 0`r`npwdLastSet: -1`r`ndisplayName: " + $obj.DisplayName + "`r`nobjectClass: user`r`nsAMAccountName: " + $alias + "`r`n"
write-output $output | out-file -filePath "c:\ldifout.ldf" -append -noClobber
}

# Function that returns true if the incoming argument is a help request
function IsHelpRequest
{
param($argument)
return ($argument -eq "-?" -or $argument -eq "-help");
}

# Function that displays the help related to this script following
# the same format provided by get-help or
-?
function Usage
{
@"

NAME:
CreateLdifFromDisconnectedMailboxes.ps1

SYNOPSIS:
Finds all disconnected mailboxes on the local server and creates an LDIF file
with an entry for each disconnected mailbox user. Use the LDIFDE utility to import this LDIF file to Active Directory, which generates the user accounts. You can then reconnect Mailboxes
to these accounts by using the Connect-Mailbox cmdlet. You can
specify a particular database, or specify no database to search all databases
on the local server.

This script is mainly used for disaster recovery scenarios where all data except
the mailbox databases have been lost. In these scenarios, without a backup of Active
Directory, you must re-create the user accounts so they can be
connected to existing mailboxes. This is the main objective of this script.

SYNTAX:
CreateLdifFromDisconnectedMailbox -ContainerDN

-Database
-Append `$false|`$true

AD Container DN is a valid Active Directory container in distinguished name format. This value
must be enclosed in quotes. Database is the Identity parameter of the
database. You can retrieve the Identity value for all databases on the local
server by running the following cmdlet:

get-mailboxdatabase -server Server01 | fl Identity

Setting -append to `$true tells the script to append data to the current
c:\ldifout.ldf file instead of overwriting it. This is the recommended
setting if you are piping output from other cmdlets to this script. If the
-append switch is not included, the script runs automatically in overwrite mode.

EXAMPLES:

"Specifying Database ID"
CreateLdifFromDisconnectedMailbox -ContainerDN "CN=Users,DC=Domain,DC=com"
-Database "SERVER\Storage Group\Database"

"Run Against All Stores on Local Server"
CreateLdifFromDisconnectedMailbox -ContainerDN "CN=Users,DC=Domain,DC=com"

"Pipe output of another cmdlet into this script"
get-mailboxdatabase -server SERVER | foreach {CreateLdifFromDisconnectedMailboxes -ContainerDN

"CN=Users,DC=domain,DC=com" -Database `$_.Identity -append `$true}
"@
}

################################################################
##########################BEGIN SCRIPT##########################
################################################################

#Check if this is a help request
$args | foreach { if (IsHelpRequest $_) { Usage; exit; } }

#Delete existing LDIF file if it is there and append is set to false
if(!$append){$a = remove-item c:\ldifout.ldf -ea SilentlyContinue}

#Validate all input parameters
$ifValidParams = ValidateParams;
if (!$ifValidParams) { exit; }

#find all disconnected mailboxes and get required information
if ($Database -ne "")
{
write "Getting disconnected mailboxes for database $Database"
$getmbxcmd = get-mailboxstatistics -Database $Database | where {$_.DisconnectDate -ne $null}
}
else
{
write "Getting disconnected mailboxes for all databases on local server."
$getmbxcmd = get-mailboxstatistics | where {$_.DisconnectDate -ne $null}
}

#Make sure at least one disconnected mailbox is found; if not, exit script
if ($getmbxcmd -eq $null) {write "No disconnected mailboxes found.";exit}

#loop through each disconnected mailbox and write entries to the output file
foreach ($entry in $getmbxcmd)
{
ExtractDisplayNameAndAlias $entry
}

write "LDIF file successfully written to C:\ldifout.ldf."

Thanks
vinod