Client Experience - Category color disappearing from item after Outlook restarts
Just recently I was working on interesting case where colors were disappearing from custom categories in Archive Calendar items after Outlook restarts.
Following are steps user done to reproduce the issue:
1. Opened calendar item from Archive mailbox,
2. Created new category and assigned custom color to it,
3. Assigned newly created color to opened calendar item,
4. Saved item,
5. Upon restarting Outlook, custom color disappeared.
First thing I wanted to check if there is actual category property set on server on the item itself. That would show if Outlook ROP (Remote OPeration) reached and updated item on the server and that we are not seeing "Test Category" string definition from local .ost file. Fired up PowerShell session and loaded Get-StoreQuery function.
From information above I knew following:
1. Items are in Calendar folder,
2. Calendar folder is in Archive mailbox.
First thing to do is find user's archive mailbox number in the store as it will be used for retrieving folders and items:
$mbx = Get-Mailbox userMailbox -Archive
$mbxNumberInStore = Get-StoreQuery -Database $mbx.ArchiveDatabase -Query "Select MailboxNumber From [$($mbx.ArchiveDatabase)].Mailbox Where MailboxGuid='$($mbx.ArchiveGuid)'"
$mbxNumberInStore
MailboxNumber
-------------
123
Then we need actual id of the calendar folder within archive since it will be used as parameter while retrieving messages:
$calendarFolderInArchive = Get-StoreQuery -Database $mbx.ArchiveDatabase -Query "Select FolderId, DisplayName From [$($mbx.ArchiveDatabase)].Folder Where MailboxNumber=$($mbxNumberInStore.MailboxNumber) and DisplayName='Calendar'"
$calendarFolderInArchive
FolderId DisplayName
-------- -----------
0x52D13AF2E8970F408FC28B30EAB9CD4B0000145ED07200000100 Calendar
At this point I needed only category stamp and subject of test calendar item (MAPI properties are documented on MSDN - MAPI Properties). Below are hex representation of MAPI properties and first 4 chars are property identifier and last for are type of data stored within property:
$keywordsProperty = p8002101F
$subjectProperty = p0037001F
Get-StoreQuery -Database $mbx.ArchiveDatabase -Query "Select $keywordsProperty, $subjectProperty From [$($mbx.ArchiveDatabase)].Message Where MailboxNumber=$($mbxNumberInStore.MailboxNumber) and FolderId=$($calendarFolderInArchive.FolderId)" | Where-Object { $_.p0037001F "Test Meeting"}
p8002101F p0037001F
--------- ---------
Test Category Test Meeting
String representation of category is stamped on item. Great, ROP is not failing and item is updated which means that client is able to talk to server and submit ROPs without any issues.
Next logical question would be - Where category color definition is stored? It is within Calendar FAI (Folder Associated Item) on IPM.Configuration.CategoryList message class item which is not visible through Outlook. Since it's not visible through Outlook I wanted to check if it's visible using Get-StoreQuery:
Note // Category definition for all items within single mailbox are store in Calendar folder of that mailbox, no matter if item flagged with category is in Inbox or any other folder.
Get-StoreQuery -Database $mbx.ArchiveDatabase -Query "Select * From [$($mbx.ArchiveDatabase)].Message Where MailboxNumber=$($mbxNumberInStore.MailboxNumber) and FolderId=$($calendarFolderInArchive.FolderId) and MessageClass='IPM.Configuration.CategoryList'"
Nothing returned! First thought was either Get-StoreQuery cannot access to the item or Archive mailbox is missing IPM.Configuration.CategoryList item. To rule out first scenario I executed Get-StoreQuery against primary mailbox and suprisingly I got result:
Get-StoreQuery -Database $mbx.Database -Query "Select * From [$($mbx.Database)].Message Where MailboxNumber=$($Numb
erInStore.MailboxNumber) and FolderId=$($calendarFolder.FolderId) and MessageClass='IPM.Configuration.CategoryList'"
MailboxNumber : 122
LastModificationTime : 30.4.2016. 16:32:52
Size : 4850
MessageClass : IPM.Configuration.CategoryList
At this point it was clear that category item (Keyword typeOf string) was successfully stamped on Calendar item (meeting item), but Outlook client wasn't able to store color definition for it in configuration store IPM.Configuration.CategoryList as this was missing from Archive mailbox configuration.
How to recreate missing IPM item and remediate issue?
Outlook have custom switch which can be used when starting - outlook.exe /remigratecategories. However in this case that didn't helped. Ews to the rescue! Since Ews supports access to FAI, I created cmdlet in Ews module which will recreate missing IPM.Configuration.CategoryList item:
Following cmdlet generates empty IPM.Configuration.CategoryList under specified folder:
$calendarArchiveFolder = Get-EwsFolder -RootFolder (Get-EwsWellKnownFolderId ArchiveRoot) -FolderName "Calendar"
Get-EwsMasterCategoryConfiguration -CalendarFolder $calendarArchiveFolder
WARNING: CategoryList item not found in specified calendar folder.
WARNING: The specified object was not found in the store., The configuration object was not found. Name = CategoryList.
New-EwsMasterCategoryConfiguration -CalendarFolder $calendarArchiveFolder
Get-EwsMasterCategoryConfiguration -CalendarFolder $calendarArchiveFolder
Name : CategoryList
ParentFolderId : AAMkAGM1NmE5NTA4LWI5Y2YtNGI0NC1hNGM2LTc3NmZmOTNjMWY0NgAuAAAAAADDlsVc+qFNQ7GQklHk1YUeAQBS0Try6JcPQI/CizDquc1LAAAAAAENAAA=
ItemId : AAMkAGM1NmE5NTA4LWI5Y2YtNGI0NC1hNGM2LTc3NmZmOTNjMWY0NgBGAAAAAADDlsVc+qFNQ7GQklHk1YUeBwBS0Try6JcPQI/CizDquc1LAAAAAAENAABS0Try6JcPQI/CizDquc1L
AAAhukKOAAA=
Dictionary : {}
XmlData :
BinaryData :
IsDirty : False
Creating new category within Archive mailbox initialized IPM.Configuration.CategoryList FAI which resolved issue completely:
$categoryPayload = Get-EwsMasterCategoryConfiguration -CalendarFolder $calendarArchiveFolder
[System.Text.Encoding]::UTF8.GetString($categoryPayload.XmlData)
<?xml version="1.0"?>
<categories>
<category name="After Repair" color="5" keyboardShortcut="0" usageCount="6" lastTimeUsedNotes="1601-01-01T00:00:00.000" lastTimeUsedJournal="1601-01-01T00:00:00.000" lastTimeUsedContacts="1601-01-01T00:00:00.000" lastTimeUsedTasks="1601-01-01T00:00:00.000" lastTimeUsedCalendar="2016-04-30T16:32:51.342" lastTimeUsedMail="1601-01-01T00:00:00.000" lastTimeUsed="2016-04-30T16:32:51.342" lastSessionUsed="2" guid="{3C9CA7C2-64DD-4942-AB47-6CE29FF23624}"/>
</categories>