D(one) IT

IT Tips, Tricks & Such

Category Archives: Exchange

Event ID: 2937 Process w3wp.exe, Property [GlobalAddressList] is pointing to the Deleted Objects container

During a restart after installing SP1 for Exchange 2010 the event log would report Event ID: 2937

Process w3wp.exe () (PID=1796). Object [CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=####]. Property [GlobalAddressList] is set to value [####/Configuration/Deleted Objects/####/DEL:42677498-dfc0-40de-bdfe-8918bacb9042], it is pointing to the Deleted Objects container in Active Directory. This property should be fixed as soon as possible.

The solution was to open ADSIEDIT and connect to the domain.

  • Expand: “Configuration”,”CN=Configuration,DC=####”,”CN=Services”
  • On the left You should see: “CN=Microsoft Exchange”
  • Right Click on the “CN=Microsoft Excahnge” container and chose properties
  • Find “globalAddressList” in the list
  • Select and click “Edit” on “globalAddressList”
  • Select and click “Remove” on the values that point to Deleted Items “0ADEL…”.
  • Click “OK”, then “Apply”, and finally “OK” again.
  • Restart Server and verify Event Log.

 

Customize Outlook Web App themes in Exchange 2010 sp1

Customizing themes for OWA requires understanding the changes Exchange 2010 sp1 has done with theme management and the addition of new themes.

OWA Theme selection (about 28 themes to choose from):

Customizing all these themes would be painful. Thankfully you can disable users from being able to change OWA themes.

  • Using EMC GUI: Disable the Theme Selection option in the segmentation tab of OWA (Default Web Site) in Client Access under Server Configuration.
  • Using PowerShell:
    set-owavirtualdirectory -identity "<servername>\owa (default web site)" -themeselectionenabled $false 

OWA Theme selection removed:

I’ll be going over modifying an existing theme. Detailed information for creating a new theme can be found: Create a Theme for Outlook Web App

The OWA themes are stored:
\Program Files\Microsoft\Exchange Server\V14\ClientAccess\Owa\<version>\themes\

*Theme location changes as Exchange service packs or rollups are installed. Customizations will need to be copied to the new path after major updates.*

To set the default theme from powershell if not modifying the base theme:

set-owavirtualdirectory -identity "<servername>\owa (default web site)" -defaulttheme NewCustomtheme

Replacing the favicon.ico and the logo used for the signon and signoff screens can be done by replacing the favicon.ico and lgntopl.gif contained in the resources folder:
\Program Files\Microsoft\Exchange Server\V14\ClientAccess\Owa\<version>\themes\resources\

  • favicon.ico (16 x 16)
  • lgntopl.gif (456 x 115)

lgntop1.gif before and after:

Updating the Logo used in OWA is a little harder as it’s contained in a sprite map in the csssprites.png file located:
\Program Files\Microsoft\Exchange Server\V14\ClientAccess\Owa\<version>\themes\<base>

looking at the csssprites.css file located in the same directory as the png shows the logo is 144 x 42:

  • .sprites-logoowa-png{background-image:url(‘csssprites.png’);background-position:-62px 0px;width: 144px;height: 42px;}

When modifying the csssprites.png file remember to keep images the same size and location as the original, otherwise major changes to the csssprites.css will be required.

csssprites.png before and after:

OWA main before and after (Including favicon.ico changes):

Exchange 2010 sp1 Mailbox export to PST

In Exchange 2010, Outlook was required to be installed on the server in order to export a mailbox to PST. This is no longer the case and the MailboxExportRequest commandlet runs without any additional requirements after the install of Exchange 2010 sp1, except the user must have the “Mailbox Import Export” role.
(http://technet.microsoft.com/en-us/library/ee633455.aspx#Exp)

Syntax:


# Export request command
New-MailboxExportRequest -Mailbox "name" -FilePath "\\uncpath\name.pst"

# Check on request status
Get-MailboxExportRequest | Get-MailboxExportRequestStatistics

# Remove request after completion
Get-MailboxExportRequest |Remove-MailboxExportRequest

Exchange 2010 sp1 OWA password reset

Exchange 2010 sp1 contains the reset user password feature in Outlook Web App, but it’s disabled by default. (http://technet.microsoft.com/en-us/library/bb684904.aspx)

To enable this feature, make the following changes on all CAS servers in your environment:

  • In registry editor, navigate to: HLKM\SYSTEM\CurrentControlSet\Services\MSExchange OWA
  • Create or modify the following DWORD entry: ChangeExpiredPasswordEnabled and set the value to 1.

Changes to OWA

ActiveSync device connection errors

While trying to connect a couple sample devices to Exchange 2010 ActiveSync, I came across the following errors while setting the test email account:

iPhone error: “The connection to the server failed”

Android error: “Unable to open connection to server”

Looking at the Exchange server’s event logs, I found EventID 1053: “Exchange ActiveSync doesn’t have sufficient permissions to create the… container under Active Directory user…”

To resolve this issue, enable the Advanced Security permission: “Include inheritable permissions from the object’s parent” for the effected user within Active Directory.

Exchange 2010 management console: “An error caused a change in the current set of domain controllers…”

While using the Exchange 2010 Management Console and navigating to the recipient mailbox, I received:

An error caused a change in the current set of domain controllers. It was running the command ‘Get-Recipient -PropertySet ConsoleLargeSet -resultSize ‘1000’ -SortBy DisplayName -RecipientType ‘UserMailbox”.

This  error started to occur shortly after the decommission of our old primary domain controller.

To fix this error, close the EMC and delete the xml file:

“C:\Users\username\AppData\Roaming\Microsoft\MMC\Exchange Management Console”

Outlook 2010 thumbnailPhoto in Active Directory

While testing Outlook 2010 on Exchange 2010, I found the GAL now supports photos (out of the box… almost)

Requirements (GAL Photos in Exchange 2010 and Outlook 2010):

  • Outlook 2010 (Note: Exchange 2010 OWA doesn’t retrieve AD photos).
  • AD forest upgraded to support 2008 domain controllers (adprep, not Function Level).
  • Modify the thumbnailPhoto attribute in AD schema to replicate to the Global Catalog.

Uploading photos into AD can be done using the Exchange cmdlet: Import-RecipientDataProperty, but is limited to a max 10k photo size.

Import-RecipientDataProperty -Identity Michael -Picture -FileData ([Byte[]]$(Get-Content -Path "S:\Staff_Photos\Michael.jpg" -Encoding Byte -ReadCount 0))

I came across this free tool: ADPhotoEdit which can push the size limit to 100k and has a pretty awesome gui. There is a paid version which includes bulk features.

Update: Outlook 2003-2007 can access the thumbnailPhoto if  the Outlook Social Connector is installed and the thumbnailPhoto property in OAB is changed from an indicator to a value. (Updating OABDeploying OSC)

Fixing Public Folder replication issues from Exchange 2003 to 2007 or 2010

During a transition of Exchange 2003 to 2010, we ran into replication issues in some of the Public Folders. The issue was tracked down to Categories that contain a bad character. Instead of going through all the entries manually, I found a replication fix script: http://blogs.technet.com/b/bill_long/archive/2010/04/22/fixing-public-folder-replication-errors-from-exchange-2003-to-exchange-2007-or-2010.aspx

Notes:

  • You might need to modify $allPFs. Change the “All Public Folders” text to match however it looks in Outlook.
  • By default the script will not change any data unless you set $commitChanges to true.
  • Power shell’s default script execution mode is Restricted, which might prevent the use of Fix-PFItems.ps1. Quick workaround is to run the following command in power shell (remember to change back to restricted when done):
    Set-ExecutionPolicy Unrestricted

Fix-PFItems.ps1 (click “show source” below)


# Fix-PFItems.ps1
#
# This script should be run on a workstation where Outlook is installed
# as well as Powershell. You do not need the Exchange Management Console
# installed in order to use this. The Outlook profile you are using should be
# one that will access public folders on the Exchange 2003 server, because
# the whole point is to fix the items on the 2003 side so they will replicate
# to Exchange 2007/2010. If you're not sure which replica of a folder your
# profile is accessing, launch MFCMapi, logon to the same profile, navigate
# to the public folder, and look at the PR_REPLICA_SERVER property. This will
# tell you which replica your client is looking at.
#
# Syntax info:
#
# Examples:
# .\Fix-PFItems -folderPath "Departments\HR" -splitOnBadchar $true -resetEmptyCategories $false -doAppointments $false -doInstanceKey $false -doSubfolders $false
# .\Fix-PFItems "Departments\HR" $true $false $false $false $false
#
# folderPath should be in the form: "TopLevelFolder\Subfolder\Subfolder 2"
# a folderPath of "" will run against all public folders
# splitOnBadChar determines whether we split the category into two names, or just replace badChar
# resetEmptyCategories will clear all categories on items that already appear to have no
#   categories. This ensures that the categories value is REALLY empty, and should fix
#   items that have an empty array in the categories. Be aware that since this changes ALL
#   items that appear to have no categories, it could cause a lot of replication.
# doAppointments determines whether appointment items are processed. Note that if this is $true
#    and $commitChanges is set to $true, ALL appointment items in the specified folders
#    will be modified by the script. This will change the last modified time and cause
#    replication.
# doInstanceKey determines whether we clear PR_INSTANCE_KEY on items. Note that if this is $true
#    and $commitChanges is set to $true, ALL items in ALL folders that you specify will be
#    be modified.
# doSubfolders determines whether we automatically traverse subfolders of the specified folder
#
# This script will identify 5 types of problems:
#
# 1. Categories that contain a bad character, typically a comma. This error is identified in the
#    content conversion tracing by output that states:
#
#    PropertyValidationException: Property validation failed. Property = [{GUID}:'Keywords']
#    Categories Error = Element 0 in the multivalue property is invalid..
#
#    This problem will always be fixed if $commitChanges is $true (see below). The
#    -splitOnBadChar parameter lets you choose whether to split the category into two separate
#    categories (A category such as "catone,cattwo" would become two separate categories
#    "catone" and "cattwo") or to simply get rid of the bad character ("catone,cattwo" becomes
#    "catonecattwo").
#
# 2. Categories that contain an emtpy array. This problem is identified by the same tracing
#    output as that shown for problem #1. This problem can be fixed if -resetEmptyCategories
#     is $true and $commitChanges is changed to $true (see below). Note that this will modify
#    all items that appear to have no categories, as the script can't tell the difference
#    between an empty array and an item that truly has no categories.
#
# 3. Appointment items with invalid start/end dates. This problem can be fixed if $doAppointments
#     is $true and $commitChanges is changed to $true. See below. Note that this does not fix
#    every possible problem with appointments.
#
# 4. Address type properties that are longer than 9 characters. This problem can be identified
#    by content conversion tracing that states:
#
#    Property validation failed. Property = [{GUID}:0x8nnn] Email2AddrType Error =
#    Email2AddrType is too long: maximum length is 9, actual length is nn..
#
#    This problem cannot be fixed by the script. You can try to fix it manually using
#    mfcmapi, but sometimes these properties cannot be changed and the item
#    must be deleted.
#
# 5. A bad PR_INSTANCE_KEY. This problem can be identified by an error in the
#    content conversion tracing that says MapiExceptionPropsDontMatch. This problem can
#    be fixed by the script if -doInstanceKey is $true and $commitChanges is $true (see
#    below).
#

param([string]$folderPath, [bool]$splitOnBadchar, [bool]$resetEmptyCategories, [bool]$doAppointments, [bool]$doInstanceKey, [bool]$doSubfolders)

#
# By default, the script does NOT change anything. You must
# change $commitChanges to $true in order for the script to actually
# do anything.
#
# This has the potential to change a lot of items in your public folders!
# Run it in READ ONLY mode first to see what will get changed, and have a
# good backup just in case!
#
$commitChanges = $false

# $badChar is the character we want to get rid of in the category names.
# Normally it's a comma, but it can be changed to anything you want.
$badChar = ","

# $reportAll will make the script report all categories and address types
# that were found. This is just for reporting purposes so you can see what values
# exist.
$reportAll = $false

#
##########################################################################
#
# Be careful changing anything below this point.
#
##########################################################################
#

$allCategories = new-object System.Collections.Specialized.StringCollection
$allAddressTypes = new-object System.Collections.Specialized.StringCollection

function GetNamedFromCollection($name, $collection)
{
 foreach ($item in $collection)
 {
 if ($item.Name -eq $name -or $item.DisplayName -eq $name)
 {
 return $item
 }
 }
 return $null
}

function RecordAddrType($type)
{
 if ($reportAll)
 {
 if (!($allAddressTypes.Contains($type)))
 {
 $temp = $allAddressTypes.Add($type)
 }
 }
}

function DoCategories($item)
{
 $categoryArray = $item.PropertyAccessor.GetProperty("urn:schemas-microsoft-com:office:office#Keywords")
 if ($categoryArray.Length -eq 0 -and $resetEmptyCategories -eq $true)
 {
 if ($commitChanges)
 {
 "    Resetting categories..."
 $item.PropertyAccessor.SetProperty("urn:schemas-microsoft-com:office:office#Keywords", $null)
 $item.Save()
 }
 else
 {
 "    Would have reset the categories, but we're in Read-Only mode."
 }
 }
 else
 {
 $fixedCategories = $false
 [string[]]$newCategoryArray = @()
 foreach ($cat in $categoryArray)
 {
 if ($reportAll)
 {
 if (!($allCategories.Contains($cat)))
 {
 $temp = $allCategories.Add($cat)
 }
 }
 if ($cat.Contains($badChar))
 {
 if (!($splitOnBadchar))
 {
 # In this case, we just replace the badChar with nothing
 $newCategoryArray += $cat.Replace($badChar, "")
 }
 else
 {
 # In this case, we split it into multiple separate categories
 $categorySplit = $cat.Split($badChar)
 foreach ($newCat in $categorySplit)
 {
 $newCat = $newCat.Trim()
 if ($newCat.Length -gt 0)
 {
 $newCategoryArray += $newCat
 }
 }
 }
 $fixedCategories = $true
 }
 elseif ($cat.Trim() -eq "")
 {
 # this category should be deleted from the item
 $fixedCategories = $true
 }
 else
 {
 $newCategoryArray += $cat
 }
 }

if ($fixedCategories)
 {
 "    Old category list for this item:"
 foreach ($cat in $categoryArray)
 {
 ("        " + $cat)
 }
 "    New category list for this item:"
 foreach ($cat in $newCategoryArray)
 {
 ("        " + $cat)
 }
 if ($commitChanges)
 {
 $item.PropertyAccessor.SetProperty("urn:schemas-microsoft-com:office:office#Keywords", $newCategoryArray)
 $item.Save()
 ("    Changes saved.")
 }
 else
 {
 ("    Changes not saved (READ ONLY mode).")
 }
 }
 }
}

function DoAppointmentProps($item)
{
 if ($item.Class -eq 26) # olAppointment in the olObjectClass enumeration is 26
 {
 if ($commitChanges)
 {
 ("    Updating appointment props: " + $item.Subject)
 if ($item.IsRecurring)
 {
 $recurPattern = $item.GetRecurrencePattern()
 $recurPattern.StartTime = $recurPattern.StartTime
 $recurPattern.EndTime = $recurPattern.EndTime
 $item.Save()
 }
 else
 {
 $item.Start = $item.Start
 $item.End = $item.End
 $item.Save()
 }
 }
 else
 {
 ("    Appointment props not updated (READ ONLY mode).")
 }
 }
}

function DoInstanceKey($item)
{
 if ($commitChanges)
 {
 ("    Clearing PR_INSTANCE_KEY: " + $item.Subject)
 $item.PropertyAccessor.DeleteProperty("<a href="http://schemas.microsoft.com/mapi/proptag/0x0FF60102%22)">http://schemas.microsoft.com/mapi/proptag/0x0FF60102")</a>
 $item.Save()
 ("    Changes saved.")
 }
 else
 {
 ("    PR_INSTANCE_KEY not cleared (READ ONLY mode).")
 }
}

function DoAddrType($item)
{
 $senderAddrType = $item.PropertyAccessor.GetProperty("<a href="http://schemas.microsoft.com/mapi/proptag/0x0C1E001E%22)">http://schemas.microsoft.com/mapi/proptag/0x0C1E001E")</a>
 RecordAddrType $senderAddrType
 if ($senderAddrType.Length -gt 9)
 {
 ("    WARNING! PR_SENDER_ADDRTYPE is too long: " + $senderAddrType)
 }

$sentRepresentingAddrType = $item.PropertyAccessor.GetProperty("<a href="http://schemas.microsoft.com/mapi/proptag/0x0064001E%22)">http://schemas.microsoft.com/mapi/proptag/0x0064001E")</a>
 RecordAddrType $sentRepresentingAddrType
 if ($sentRepresentingAddrType.Length -gt 9)
 {
 ("    WARNING! PR_SENT_REPRESENTING_ADDRTYPE is too long: " + $sentRepresentingAddrType)
 }

$recipients = $item.Recipients
 if ($recipients -ne $null)
 {
 foreach ($recipient in $recipients)
 {
 $addrType = $recipient.PropertyAccessor.GetProperty("<a href="http://schemas.microsoft.com/mapi/proptag/0x3002001E%22)">http://schemas.microsoft.com/mapi/proptag/0x3002001E")</a>
 if ($addrType.Length -gt 9)
 {
 ("    WARNING! A recipient PR_ADDRTYPE is too long: " + $addrType)
 }
 }
 }

if ($item.Email1AddressType.Length -gt 0)
 {
 RecordAddrType $item.Email1AddressType
 }
 if ($item.Email1AddressType.Length -gt 9)
 {
 ("    WARNING! Email1AddressType is too long: " + $item.Email1AddressType)
 }

if ($item.Email2AddressType.Length -gt 0)
 {
 RecordAddrType $item.Email2AddressType
 }
 if ($item.Email2AddressType.Length -gt 9)
 {
 ("    WARNING! Email2AddressType is too long: " + $item.Email2AddressType)
 }

if ($item.Email3AddressType.Length -gt 0)
 {
 RecordAddrType $item.Email3AddressType
 }
 if ($item.Email3AddressType.Length -gt 9)
 {
 ("    WARNING! Email3AddressType is too long: " + $item.Email3AddressType)
 }
}

function DoFolder($folder)
{
 $replicaServer = $folder.PropertyAccessor.GetProperty("<a href="http://schemas.microsoft.com/mapi/proptag/0x6644001E%22)">http://schemas.microsoft.com/mapi/proptag/0x6644001E")</a>
 $items = $folder.Items
 ($items.Count.ToString() + " items found in folder " + $folder.FolderPath)
 ("Accessing this folder on server: " + $replicaServer)
 foreach ($item in $items)
 {
 ("Checking item: " + $item.Subject)
 if ($item.PropertyAccessor -ne $null)
 {
 DoCategories($item)
 DoAddrType($item)
 if ($doAppointments)
 {
 DoAppointmentProps($item)
 }
 if ($doInstanceKey)
 {
 DoInstanceKey($item)
 }
 }
 else
 {
 "    No PropertyAccessor on this item. It may be in a conflict state."
 }
 }
 if ($doSubfolders)
 {
 foreach ($subfolder in $folder.Folders)
 {
 DoFolder($subfolder)
 }
 }
}

"Starting..."

if ($commitChanges)
{
 "commitChanges has been set to TRUE. The script WILL save changes."
}
else
{
 "commitChanges is set to FALSE. Running in READ ONLY mode. Changes will NOT be saved."
}

$outlook = new-object -com Outlook.Application
if (!($outlook.Version -like "12.*" -or $outlook.Version -like "14.*"))
{
 ("This script requires Outlook 2007 or 2010. Your version: " + $outlook.Version)
 return
}
$mapi = $outlook.GetNamespace("MAPI")

#
# First, check the categories list and fix if necessary
#

"Checking Outlook categories list..."
$categories = $mapi.Categories
foreach ($category in $categories)
{
 if ($category.Name -ne $null)
 {
 if ($category.Name.Contains($badChar))
 {
 [string[]]$newNames = @()
 ("    Fixing category in Outlook category list: " + $category.Name)
 if (!($splitOnBadchar))
 {
 # In this case, we just replace the badChar with nothing
 $newName += $category.Name.Replace($badChar, "")
 }
 else
 {
 # In this case, we split it into multiple separate categories
 $categorySplit = $category.Name.Split($badChar)
 foreach ($newCat in $categorySplit)
 {
 if ($newCat.Length -gt 0)
 {
 $newNames += $newCat
 }
 }
 }
 if ($commitChanges)
 {
 $foo = $categories.Remove($category.Name)
 foreach ($newName in $newNames)
 {
 $foo = $categories.Add($newName)
 }
 }
 }
 }
}

#
# Categories list should be in good shape now.
# Now find the specified folder.
#

"Finding the specified folder..."
$session = $mapi.Session
$pfStore = $null
foreach ($store in $mapi.Stores)
{
 if ($store.ExchangeStoreType -eq 2)
 {
 $pfStore = $store
 }
}
$pfRoot = $pfStore.GetRootFolder()
$allPFs = GetNamedFromCollection "All Public Folders" $pfRoot.Folders
if ($allPFs -eq $null)
{
 "Couldn't find All Public Folders folder."
 return
}

if ($pfStore -eq $null)
{
 "Couldn't find public folder store."
 return
}

$pfRoot = $pfStore.GetRootFolder()

$folderPath = $folderPath.Trim("\")
$folderPathSplit = $folderPath.Split("\")
$folder = $allPFs

if ($folderPath.Length -gt 0)
{
 "Traversing folder path..."
 for ($x = 0; $x -lt $folderPathSplit.Length; $x++)
 {
 $folder = GetNamedFromCollection $folderPathSplit[$x] $folder.Folders
 }
 if ($folder -eq $null)
 {
 ("Could not find folder: " + $folderPath)
 return
 }
 ("Found folder: " + $folder.FolderPath)
}

#
# Got the folder.
# Start processing the folder and subfolders.
#

DoFolder $folder

"Done!"

if ($reportAll)
{
 ""
 "Categories found:"
 $allCategories
 ""
 "Address types found:"
 $allAddressTypes
}

Outlook 2003 folder refresh and new mail notification issues with Exchange 2010

After the transition of Exchange 2003 to 2010, we noticed a few issues with Outlook 2003 (online mode, not cached). Users were complaining about slow response, mail notification and folder refresh issues. The problem occurs in Outlook versions prior to 2007 due to Exchange 2010 not issuing UDP notifications.

During Microsoft Tech-Days 2010, Dave Kawula mentioned the same problem and possible solutions: http://www.insidetheregistry.com/content/viewarticle.aspx?articleid=1974

The solution for our environment was to follow KB2009942 and apply a 5 second max polling frequency to our CAS server.