Folder class conversion from IPF.Imap to IPF.Note using EWS Managed API 2.2 and Application Impersonation, in Exchange Online
As a result of a discussion that I had with one of my colleagues after publishing the article about folders deletion using EWS Managed API in EXO, I got as hint a new article idea that could sort out an old issue that is seen in the cloud, as well as in the on-premises environments.
Personally, I never confronted with such a scenario, but I know that sometimes when migrations are being performed from an IMAP messaging system to Office 365, a part of the migrated folders could become invisible. This behavior is being noticed, no matter if the user connects to his/her mailbox with an Exchange ActiveSync client, with Outlook or with OWA.
This issue is discussed in the following KB article: https://support.microsoft.com/en-us/kb/3050475, and I created the script below to check the folder class of all the folders within a given mailbox, and change it from "IPF.Imap" to "IPF.Note", when it is the case.
I hope you'll find this article useful and that it will make your life easier.
Prerequisites:
-Create a new RBAC group from Exchange Admin Center – Permissions – Admin Roles. Add the ‘ApplicationImpersonation’ role to the group and add as member, the service account that will connect to the mailboxes from UserAccounts.txt with Impersonation (it can be your Global Admin account)
-Create a log file under C:\Temp\Log.txt.
-Create a file with the impacted user mailboxes: “UserAccounts.txt”
WindowsEmailAddress
user1@domain.onmicrosoft.com
user2@domain.onmicrosoft.com
user3@domain.onmicrosoft.com
DISCLAIMER: This application is a sample application. The sample is provided "as is" without warranty of any kind. Microsoft further disclaims all implied warranties including without limitation any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the samples remains with you. in no event shall Microsoft or its suppliers be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss arising out of the use of or inability to use the samples, even if Microsoft has been advised of the possibility of such damages). Because some states do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to you.
# The script requires EWS Managed API 2.2, which can be downloaded here:
https://www.microsoft.com/en-gb/download/details.aspx?id=42951
# Make sure the Import-Module command matches the Microsoft.Exchange.WebServices.dll location of EWS Managed API, chosen during the installation
[string]$info = "White" # Color for informational messages
[string]$warning = "Yellow" # Color for warning messages
[string]$error = "Red" # Color for error messages
[string]$LogFile = "C:\Temp\Log.txt" # Path of the Log File
function SearchFolder($MailboxName)
{
#Change the user to impersonate
$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$MailboxName)
$oFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1)
$oFolderView.Traversal = [Microsoft.Exchange.Webservices.Data.FolderTraversal]::Deep
$oSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$FolderName)
$oFindFolderResults = $service.FindFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$oSearchFilter,$oFolderView)
if ($oFindFolderResults.folderclass -match "IPF.IMAP") {
write-host "Working on" $MailboxName "to update the folder class" -foregroundcolor $info
$oFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$oFindFolderResults.Id)
write-host "Folder class for" $FolderName "is" $oFindFolderResults.folderclass -foregroundcolor $warning
$oFolder.folderclass = "IPF.Note"
Write-Host "Updating folder $FolderName to correct type" $oFolder.folderclass -foregroundcolor $warning
$oFolder.update()
$i=1
}
}
Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList Exchange2013_SP1
#Provide the credentials of the O365 account that has impersonation rights on the mailboxes declared in UserAccounts.txt
$service.Credentials = new-object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList "user@domain.onmicrosoft.com","Password"
#Exchange Online URL
$service.Url= new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx")
#Read the data
import-csv "C:\Users\a-castre\Documents\Application Impersonation Blog\UserAccounts.txt" | foreach-object {
$WindowsEmailAddress = $_.WindowsEmailAddress.ToString()
(Get-MailboxFolderStatistics $WindowsEmailAddress).Name | foreach-object {
$FolderName = $_
#Catch the errors
trap [System.Exception]
{
Write-host ("Error: " + $_.Exception.Message) -foregroundcolor $error
Add-Content $LogFile ("Error: " + $_.Exception.Message)
continue
}
SearchFolder($WindowsEmailAddress)
}
$service.ImpersonatedUserId = $null
if ($i -eq $null) { Write-Host "There aren't anymore folders of type IPF.IMAP in the mailbox" $WindowsEmailAddress -foregroundcolor $warning }
}
Note: In order to run the script above, you have to copy paste it into a Notepad file and save it with the extension ".ps1". Then, you have to connect to Exchange Online with PowerShell and run it: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx.
Comments
- Anonymous
June 09, 2017
Hi, i have problem with script; i have check impersonation role it's ok but i have this errorError: Impossibile trovare la proprietà 'ImpersonatedUserId' in questo oggetto. Verificare che esista e sia impostabile.- Anonymous
June 09, 2017
Hi,Make sure that you don't forget to mention the credentials for the account with impersonation rights .$service.Credentials = new-object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList "user@domain.onmicrosoft.com","Password"
- Anonymous