Converting item and folder IDs via the Graph API

In the Exchange world, items (and folders) can be represented by several different identifiers, depending on the interface used. As detailed in the documentation, those unique-valued identifiers include:

  • EwsId – the identifier returned in operations performed via the EWS API. For example, when you do a search for messages or enumerate folders in a mailbox, the object returned will return this value in the Id (UniqueId) property. Here’s how a sample value looks like:
    AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQAuAAAAAABCOIqaOs9mS5duvcGwkHhzAQAg/oCKFU2uQqU6r5NcDVwAAACcapkwAAA=

    Another place where you will find the EwsId is as part of the URL when opening messages in OWA, for example:

    https://outlook.office.com/owa/sharednew@michev.info/?viewmodel=ReadMessageItem&ItemID=AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg%2foCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg%2foCKFU2uQqU6r5NcDVwAAAKtgxPpAAA%3d
  • EntryId – the MAPI identifier for the item/folder, corresponding to the binary PR_ENTRYID property. The value is Base64-encoded and looks something like this:
    AAAAAEI4ipo6z2ZLl269wbCQeHMBACD+gIoVTa5CpTqvk1wNXAAAAAAAAQwAAA==
  • HexEntryId – the hex-encoded representation of the EntryID. Here’s a sample value:
    0000000042388A9A3ACF664B976EBDC1B0907873010020FE808A154DAE42A53AAF935C0D5C0000000000010C0000
  • StoreId – the Exchange store identifier, which you can find for example in the output of Get-MailboxFolderStatistics cmdlet. Among other things, this value is used for generating folder IDs for use with the targeted collection Content search functionality. Here’s a sample value:
    LgAAAABCOIqaOs9mS5duvcGwkHhzAQAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAB
  • OwaId – as the name suggests, used by the web client. Basically an URL-safe representation of the StoreId. A sample value looks like this:
    LgAAAABCOIqaOs9mS5duvcGwkHhzAQAg%2FoCKFU2uQqU6r5NcDVwAAAAAAAEMAAAB
  • RestId – the default format used by the Graph API. Basically an URL-safe representation of the EntryId. Here’s an example:
    AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg-oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg-oCKFU2uQqU6r5NcDVwAAAKtgxPpAAA=
  • RestImmutableEntryId – the ImmutableID format used by the Graph API. Sample string below:
    AAkALgAAAAAAHYQDEapmEc2byACqAC-EWg0AIP6AihVNrkKlOq_TXA1cAAACrYM5GAAA
  • EwsLegacyId – used by the initial EWS version and only added for completeness.

Whenever you need to convert between those values, the ConvertId method comes to help. For example, the below EWS code will convert the EwsId of an item returned via the search operation ($fiItems[0].Items[0].Id.UniqueId) to all the other Id types:

$aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId
$aiItem.Mailbox = "sharednew@michev.info"
$aiItem.UniqueId = $fiItems[0].Items[0].Id.UniqueId
$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::EWSId

$aiItem.UniqueId
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EntryId)
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::HexEntryId)
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::StoreId)
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::OwaId)

AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg/oCKFU2uQqU6r5NcDVwAAAKtgxPpAAA=


UniqueId                                                                                                                                     Mailbox               IsArchive     Format
--------                                                                                                                                     -------               ---------     ------
AAAAAEI4ipo6z2ZLl269wbCQeHMHACD+gIoVTa5CpTqvk1wNXAAAAAAAAQwAACD+gIoVTa5CpTqvk1wNXAAAAq2DE+kAAA==                                             sharednew@michev.info     False    EntryId
0000000042388A9A3ACF664B976EBDC1B0907873070020FE808A154DAE42A53AAF935C0D5C0000000000010C000020FE808A154DAE42A53AAF935C0D5C000002AD8313E90000 sharednew@michev.info     False HexEntryId
RgAAAABCOIqaOs9mS5duvcGwkHhzBwAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg/oCKFU2uQqU6r5NcDVwAAAKtgxPpAAAA                                             sharednew@michev.info     False    StoreId
RgAAAABCOIqaOs9mS5duvcGwkHhzBwAg%2FoCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg%2FoCKFU2uQqU6r5NcDVwAAAKtgxPpAAAA                                         sharednew@michev.info     False      OwaId

Now, this is all very well known. The reason for writing an article on this is the recently introduced Graph API endpoint that allows you to perform the same operation via the Graph, and in addition allows the conversion to RestId. That, and the fact that it actually helps me remember stuff, once I put it in a blog post 🙂

As with any other Graph operations, you need to run the request against the corresponding endpoint, namely /translateExchangeIds. You will need to provide a collection of identifiers to convert, and the types between the conversion should happen. Even if you have a single identifier to convert, you must provide a collection, otherwise you will get a Bad request error, so remember that. One other important thing to remember is that the Graph uses URL-safe encoding, so if you are providing an EwsId, EntryId or StoreId, you need to prepare the strings correspondingly. Finally you put it all together in as a JSON-formatted string in a POST request.

The below example takes the EntryId of the same item we used for the EWS ConvertId operation, and asks the Graph to return the EwsId. Comparing the two examples shows the exact same value, so the operation was a success. We then ask to return the ImmutableEntryId:

#Graph uses URL-safe encoding, work around it
$sourceID = ("AAAAAEI4ipo6z2ZLl269wbCQeHMHACD+gIoVTa5CpTqvk1wNXAAAAAAAAQwAACD+gIoVTa5CpTqvk1wNXAAAAq2DE+kAAA==" -replace "\+","-") -replace "/","_"
$countToReplace = ($sourceID.ToCharArray() | ? {$_ -eq "="}).Count
$sourceID = $sourceID.TrimEnd("=") + $countToReplace

$body = @{
"inputIds"= @($sourceID)
"sourceIdType"= "entryId"
"targetIdType"= "ewsId"
} | ConvertTo-Json
$res = Invoke-RestMethod -Method Post -Uri "https://graph.microsoft.com/v1.0/users/sharednew@Michev.info/translateExchangeIds" -Headers $authHeader -Verbose -ContentType "application/json" -Body $body
$res.value.targetId

$body = @{
"inputIds"= @($sourceID)
"sourceIdType"= "entryId"
"targetIdType"= "immutableEntryId"
} | ConvertTo-Json
$res = Invoke-RestMethod -Method Post -Uri "https://graph.microsoft.com/v1.0/users/sharednew@Michev.info/translateExchangeIds" -Headers $authHeader -Verbose -ContentType "application/json" -Body $body
$res.value.targetId

AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg/oCKFU2uQqU6r5NcDVwAAAKtgxPpAAA=

AAAAAB2EAxGqZhHNm8gAqgAvxFoNACD-gIoVTa5CpTqvk1wNXAAAAq2DORgAAA2

As with any other Graph code, you need to provide authentication headers, the corresponding operations are skipped in the above examples. For additional details, check out the official documentation.

As a last remark, the ImmutableEntryId and RestImmutableEntryId don’t seem to be supported for Folder objects, but you should be able to run other conversion operations against folders as well.

This entry was posted in Exchange Online, Graph API, Office 365, Outlook, OWA. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *