Removing Duplicate Contact Items in a Exchange Mailbox

Scenario:  You have a mailbox that has hundreds of copies of their contacts in their mailbox.  For example, a user originally had 2500 contacts and now has 800,000 contacts because of the multiple copies.   Here are the steps I followed to resolve this issue.

1. Export their contacts in the users Outlook to a CSV.   In my scenario, the outlook session was locking up so I exported the PST out via Exchange Shell and then re-exported to a CSV out of Outlook. (New-MailboxExportRequest mailbox -IncludeFolders “#Contacts#” -ExcludeDumpster -FilePath servershare$contacts.pst -name mailbox  -acceptlargedataloss -baditemlimit 999)

Outlook 2013:  File–>Open&Export–>Import/Export–>Export to a File–>Comma Separated Values–>Select Contacts Folder–>Save Exported File to location –> Click Finish.

2. Open Powershell, and Import the CSV created in step 1 into a Variable.
$File = Import-CSV “C:usersusernamedesktopuserscontacts.csv”

3. Select the unique values for the $File, compares all columns.
$uniq = $File | Select * -unique

4. Export the unique values to a .csv file
$uniq | Export-csv “C:usersusernamedesktopuserscontacts_unique.csv”

5. Delete the existing contacts in the users mailbox via Exchange Shell.  The Search-Mailbox has a 10,000 item limit. I put the command in a loop so it continues to remove all contacts at 10,000 per loop cycle.

do {
Write-Host $i
Search-Mailbox mailbox -SearchQuery kind:contacts -DeleteContent -Force
$i++
}
while ($i -le 81)

6. Opened Outlook 2013 and followed similar steps as step 1, except I performed the import on the unique CSV.  Note, I did have to clean up the CSV by removing the very first line as the very first line was not the column names.  In order for the CSV import to work, the first line needs to be the column names and NOT the other junk that export may have carried over.

Now the unique contacts are restored.

Find a Message in the message tracking log against every transport server in your Exchange Org

The Powershell one liner below will search the Message Tracking Log against every transport server in your Exchange Organization.  Note that you may want to change the Select statement to include/remove which values you want to pull back into view (you can replace with the entire Select statement with FL to see every value available).

Get-TransportServer | Get-MessageTrackingLog -Sender:user@domain.com -Recipients user@domain.com -MessageSubject “another test” -Start 5/8/2014 | Sort Timestamp | Select TimeStamp, EventID, Source, MessageSubject, ClientIP, ClientHostname, ServerIP, ServerHostname

Exchange PowerShell script that will perform a mailbox count on each database and email the results.

Below is a Exchange PowerShell script that will perform a mailbox count on each database and email the results.  The script is performed with the get-mailboxstatistics for each mailbox on that database as the results are much faster than the get-mailbox command.


# Create an empty HashTable to store database name and count.
$MailboxCount = @{}

# Collect Databases
$databases = Get-mailboxDatabase | Where Name -like “2013DB*” | Sort name

#Loop through each
ForEach ($database in $databases){
$MBs = Get-mailboxstatistics -database $database
$MailboxCount.Add($Database,$MBs.count)
}

#Format the Results
$MailboxCountOrdered = $MailboxCount.GetEnumerator() | Sort-Object Name | Out-String
$orderedMailboxCount = $MailboxCount.GetEnumerator() | Sort-object Value | Out-String

#Send an email:
$SmtpClient = new-object system.net.mail.smtpClient 
$MailMessage = New-Object system.net.mail.mailmessage 
$SmtpClient.Host = “mail.server.com” 
$mailmessage.from = (“MailboxCount@domain.com”) 
$mailmessage.To.add(“email.address”) 
$mailmessage.Subject = “Mailbox Count”
$mailmessage.Body = “Mailbox Count

The following list shows the Mailbox Count for the Databases in Ex2013. The 2 lists below are the same; one is in order of database name and the other is in order of mailbox count.
Database Order:
$MailboxCountOrdered 
Count Order:
$OrderedMailboxCount

$smtpclient.Send($mailmessage)

Rolling and Redistributing Databases

Rolling Databases to other Servers

PS Script  – Note: we have a csv file that has the databasenames and the server we want to move to that the script calls. In the csv it has a db and a server column.

import-csv movedb_Ex2010.csv | foreach {Move-ActiveMailboxDatabase $_.DB -ActivateOnServer $_.Server -MountDialOverride:Lossless -confirm:$false}

Status of Script:  Check mounted databases
Get-MailboxServer | Where {$_.Name -like “Server*”} | Get-MailboxDatabaseCopyStatus | Where {$_.Status -like “Mounted”}

Troubleshooting:  

  • Check the health of the database copies: Get-MailboxDatabaseCopyStatus database
  • Manually roll a database, run the following command:   Move-ActiveMailboxDatabase databasename –ActivateOnServer servername –MountDialOverride:Lossless –confirm:$false

Redistributing Databases 

PS command: From the <exchange dir>scripts directory, run the following: 

.RedistributeActiveDatabases.ps1 -DagName dagname -BalanceDbsByActivationPreference –ShowFinalDatabaseDistribution –Confirm:$false


Troubleshooting: 
If the databases did not mount on the server they should have, check for databasecopystatus on that server or give it some time to try again.

You can run Get-MailboxDatabaseCopyStatus databasename to check to see the database copy health.

You can run Move-ActiveMailboxDatabase databasename –ActivateOnServer servername –MountDialOverride:Lossless –confirm:$false to manually move the database to another server.

If the ContentIndexState on the database copies is failed and it does become healthy after time, you could reseed just the ContentIndex by using this command: update-mailboxdatabasecopy databasenameservername –CatalogOnly

If the ContentIndexState is failed on the databasecopies with the same server, you may have to restart that server again.

To run a report on the Health of the databasecopies after a redistribute is finished, run the following:

Get-MailboxServer | Where {$_.name -like “server*”} | Get-MailboxDatabaseCopyStatus | Select Name, Status, ContentIndexState 

Export Message Tracking Log for a Specific Sender after a certain day

Scenario: Export the message tracking log for a specific sender after certain day to a .csv

Get-TransportServer | Get-MessageTrackingLog -Sender user@domain.com -Start 3/19/2014 | Where EventID -like “Send” | Select MessageSubject, ClientIP, ClientHostname, Timestamp, {$_.Recipients} | Export-csv C:usersusernamedesktopmessagetrackinglog.csv

Note: the Recipients is enclosed in {$_. }. This is because the recipients property is an array that can hold multiple values and it does not export correctly if referenced without the additional formatting.

Validate if an Exchange Retention Policy is applied to a mailbox item

Scenario:  You have applied a Exchange Retention Policy to a mailbox and the mailbox items that you expected to delete, may not be deleting right away.

To see if a mailbox item has a retention policy applied, perform the following:
1. Open MFCMAPI
2. Connect to your Outlook Profile via Session–>Logon.
3. Open your mailbox by right clicking your displayname and choose Open Store.
4. Expand out the Root Container –> Top of Information Store.
5. Right click on the mail folder that should have the retention applied and Open Contents Table.
6. Locate an email and find the PR_RETENTION_DATE Property.  The value should contain the date for when the retention will process on the item.
This may tell you the date for when the item may be deleted.  If you believe the retention policy is not getting applied, you could adjust the work cycle by extending it from 1 day to 3 days.  The work cycle is a background process that is throttled, therefore may not be able to get to all the mailboxes in a single days work cycle.

Exchange PowerShell script to search a mailbox based on Message Class

Scenario:  You want to search a mailbox via PowerShell for any messages of a specific message class.

The link below contains a script that can be downloaded. I ran it from PowerShell to look for a CommVault message class (IPM.Note.Commvault.Galaxy.Stub) that would show if we have any stubbed messages in a users mailbox with success. Note: I had to change the location of the webservices.dll in the script.

.Search-MailboxForMessageClass.ps1 user@domain.com IPM.Note.Commvault.Galaxy.STub

PowerShell: Search mailbox for items of a particular message class (ItemClass)

Exchange script to delete email items within a date range against a mailbox

Scenario:   You want to delete mail items (not calendar or contact items) from all mailbox folders in a mailbox. The script performs a query for all email items between a date range.

Script:
$startdate = ’01/01/1900′   #specifies start date
$enddate = (get-date).adddays(-60)  #specifies end date by subtracting 60 days
$enddate = $enddate.ToShortDateString()  #converts end date to string.

$users = Import-csv C:scriptusers.csv   #imports list of users with the column heading ‘name’

#Deletes email content between the two dates for each mailbox.
$users | ForEach {
search-mailbox $_.name -searchquery “kind:email AND Received:$startdate..$enddate” -deletecontent -force
}

Search-Mailbox has a 10,000 item limit that search-mailbox before it stops processing. Put it in a loop and let it run. The example below is for a single mailbox outside of the script above.

do {
 Write-Host $i
search-mailbox mailboxname -searchquery “kind:email AND Received:1/1/1900..12/31/2012” -deletecontent -force
 $i++
 }
 while ($i -le 30)

Reporting on the Item Age (Count and Size) in a Mailbox using EWS and Powershell

Reporting on the Item Age (Count and Size) in a Mailbox using EWS and Powershell

This article has two really good scripts:
http://gsexdev.blogspot.com/2012/10/reporting-on-item-age-count-and-size-in.html

1. A summary script for collecting an ItemCount and Size by Year for message items in a mailbox.
2. A detailed script for collecting information on ItemCount and Size by Year and by Mailbox Folder for message items in a mailbox.

Here are some tips I had to do to get it to run:
1. I used mailboxname like this:  $MailboxName = “user@domain.com” in place of $args[0].
2. I had to change the path of the Microsoft.Exchange.WebServices.dll.
3. I changed the ExchangeVersion to match my current version.
4. I had to give the account I was authenticating full permissions to the mailbox I was running against:  add-mailboxpermission mbox -user username -accessrights fullaccess
5. When running the script and getting prompted for authentication, I had to authenticate with a upn (user@domain.com) and not using domainuser.
6. I had to adjust the out-file to a writable location.