With the introduction of Exchange 2010 at the end of 2009, a native feature was added to Exchange Server for which organizations required 3rd party products before that. The feature which I am talking about is Exchange’s Personal Archives, Online Archives, or In-Place Archiving as it is called nowadays.
Background
Archives were introduced at a time when Office 365 was in its early days, many organizations were running Exchange on-premises with mailbox quotas as bandwidth and storage were limited or relatively expensive. It was up to end users to make sure their mailbox remained within its limits, either by removing either old items, large items or just move them out of their mailbox to those pesky .PST files.
Archives introduced benefits such as lowering disk footprint by taking infrequently used items out of the primary mailbox (which then could only synchronize in full) to the archive, which is basically an additional mailbox for long-term storage. Exchange’s built-in Messaging Records Management (MRM) through retention policies and tags can be used for automatic moving of older items to the archive.
Archives also come with few downsides, especially in the early days. Most notably are perhaps clients not supporting archives at all, or searches not spanning both mailbox and archive. Also, and this is not to be underestimated, end users do not always grasp the concept of archives and the impact on the tasks and tools they use. It’s not uncommon to see people panicking about “missing data” in service tickets, only to discover their “missing data” was moved to their archive by the company retention policy after some digging.
In recent years, I have seen archives becoming less relevant, and organizations adopting the large mailbox concept in favor of lean and mean mailboxes with archives. There are still exceptions of course, usually in the form of substantial – usually shared – mailboxes. For those, staying with Exchange Online archives – and when needed auto-expanding archives – is usually still an option due to the different type of mailbox interaction, or to circumvent Exchange’s storage limitations or Outlook for Desktop’s synchronizing of offline cache files before issues might be seen. The maximum number of items per folder is such a limit, however these have been raised or done away with in recent years. Non-stubbing 3rd party archive solutions taking data out of Exchange can also be a option.
The Problem
Switching to the large mailbox concept creates a problem for those organizations that have already enabled in-place archives for their end users: How to get that data back from those archives to the primary mailbox. While retention policies can move data in opposite direction, there is no such thing as a reverse-retention policy. Also, not every organization would like to instruct end users to unarchive this contents themselves, as it is prone to failure, blocks Outlook for Desktop from doing anything else and might result in abandoned operations which limits future actions as moves are still happening in the background.
When investigating a possible solution I found that there is no other way to accomplish this, than to programmatically move contents from the in-place archive to the primary mailbox. While there is a ‘archive’ operation for mailbox items (which moves it to the assigned Archive folder, not the in-place archive) there is no other single API call to perform this task. Also, the solution would have to use Exchange Web Services, as a limitation in Microsoft Graph makes it incapable of moving messages between multiple mailboxes.
Note: If I overlooked something in this area, please let me know.
Solution
To help organizations accomplish this task, I wrote a PowerShell script which requires the following:
- Exchange Server 2013 SP1 or later, or Exchange Online.
- Exchange Web Services (EWS) Managed API 2.21 or later (how to, NuGet package exchange.webservices.managed.api).
- When using OAuth, the MSAL library is required (NuGet package Microsoft.Identity.Client). Also, you need to have registered an App in Azure Active Directory; the Tenant ID, Application ID and certificate or secret is what you need to provide the script with to operate successfully.
- In addition to installing the NuGet packages, you can also store the DLLs in the same folder as the script.
Note: Untested with Primary mailboxes on-premises and Exchange Online Archives.
The script Invoke-Unarchive will perform the following tasks:
- Invoke-Unarchive will move contents from the in-place archive back to the primary mailbox.
- The most optimal operation will be chosen:
- Folders present in archive but not in primary mailbox will be moved in one operation.
- Folders present in archive and primary mailbox are merged. Items in those folders are moved in batches.
- The same steps are repeated recursively per folder for the whole archive.
- If, after moving, a folder in the archive is empty, and it is not a non-removable well-known folder, it will be removed.
- Optionally, Invoke-Unarchive can also move contents stored in the Recoverable Items from the archive to the primary mailbox.
- Invoke-Unarchive will handle throttling, either by honoring the returned back-off period or by adding delays between operations.
- Moving items is asynchronous, and Invoke-Unarchive needs to wait for Exchange to complete the previous move to folder X before it can move the next set of items to folder X.
Do not forget to reassign retention policies causing archival, or you might have the run the script again at later moment.
Syntax
The parameters to call Invoke-Unarchive.ps1 are:
- Identity to specify one or more mailboxes to unarchive items for.
- Server to specify the FQDN of the Client Access Server to use. When omitted, Autodiscover will be used.
- IncludeRecoverableItems to instruct the script to process deletions stored in the Recoverable Items as well.
- Impersonation to use impersonation when accessing the mailbox. When using modern authentication (OAuth), impersonation is mandatory.
- Force to force moving of items without prompting.
- NoProgressBar to prevent progress status.
- TrustAll to accept all certificates including self-signed certificates.
- TenantId specifies the ID of the Tenant when using a mailbox hosted in Exchange Online.
- ClientId to specify the Application ID of the registered application in Azure Active Directory.
- Credentials to specify the Basic Authentication credentials for on-premises usage or against Exchange Online when OAuth is not an option.
- CertificateThumbprint is the thumbprint of the certificate to use for OAuth. The certificate with the public key needs to stored with the registered application for authentication. The certificate with the private key should be present in the local certificate store.
- CertificateFile and CertificatePassword to specify the file of the certificate to use. The file shoud contain the private key, and the password to unlock the file can be specified using CertificatePassword.
- Secret can be used to specify the secret to authenticate using the registered application.
Note that Credentials, CertificateThumbprint, CertificateFile + CertificatePassword and Secret are mutually exclusive.
Example
Below shows an example run against a test-mailbox using modern authentication (OAuth). The common parameter Verbose is used to display additional output.
.\Invoke-Unarchive.ps1 -Identity michel@myexchangelabs.com -Server outlook.office365.com -Impersonation -Secret <Secret> -TenantId <Tenant> -ClientId <AppId> -Verbose

You can find the script on GitHub here.
Final Notes
The EWS operation – especially moving items – is not necessarily slow, but against Exchange Online processing large archives can take considerable amount of time due to throttling. When moving a significant number of items using Outlook for Desktop, you will likely run into Outlook abandoning the operation after which you need to wait for Exchange to finish pending moves before you can continue with this task. Using the script, you can take away this unarchiving task from end users by running the operation in the background in one or multiple runs.

Hi Michel,
Thank you for providing this tool, it looks like it will truly save my bacon.
However, I’m experiencing issues when moving some mailboxes, it appears to throttle every time. I’m initiating larger mailboxes.
Have you experienced this and is there a possible workaround?
Here’s the exact error I’m receiving:
Folder \Inbox exists, merging contents to unarchive 2871 item(s) and 10 folder(s)
VERBOSE: Collecting folders to unarchive in \Inbox
VERBOSE: Retrieving items to unarchive from \Inbox ..
VERBOSE: Discovered 2871 items in \Inbox
VERBOSE: Unarchiving 50/2871 item(s) from \Inbox
WARNING: EWS operation failed (), will retry later
WARNING: Previous EWS operation failed, waiting for 1500ms
WARNING: EWS operation failed (), will retry later
WARNING: Previous EWS operation failed, waiting for 2250ms
WARNING: EWS operation failed (), will retry later
WARNING: Previous EWS operation failed, waiting for 3375ms
WARNING: EWS operation failed (ErrorServerBusy), will retry later
WARNING: Throttling detected; server requested us to backoff for 316848ms
LikeLike
Unfortunately, cannot do a lot about getting throttled. I have on the to do list to add unarchiving to a (sub)folder, because merging takes substantially longer and hits throttling quickly (multiple calls to process things at item-level) than moving back a folder (single call operation).
LikeLiked by 1 person
Not used this yet but this looks brilliant and is exactly what I was looking for. Will be running some tests with this soon and can leave some better feedback. Will also keep an eye out for the addition of the “unarchiving to a subfolder rather than merging” as that will help – especially with the amount of mailboxes I’m going to run this against.
LikeLike
Hi,
I installed Microsoft.Identity.Client silently to skip the dependency because i was constantly getting error of dependency loop. Now you can see in following transcript i have Module installed,
PS C:\Users\userx\OneDrive\Common Need To Know\PowerShell\Invoke-Unarchive-main> Install-Package Microsoft.Identity.Client -ProviderName NuGet -Verbose
VERBOSE: Using the provider ‘NuGet’ for searching packages.
VERBOSE: Searching repository ‘https://www.nuget.org/api/v2/FindPackagesById()?id=’Microsoft.Identity.Client” for ”.
VERBOSE: Total package yield:’1’ for the specified package ‘Microsoft.Identity.Client’.
VERBOSE: Skipping installed package Microsoft.Identity.Client 4.42.1.
but when i try to run the command it gives me following error of Dll.
PS C:\Users\userx\OneDrive\Common Need To Know\PowerShell\Invoke-Unarchive-main> .\Invoke-Unarchive.ps1 -Identity TestArchive@noveltypharma.onmicrosoft.com -Credentials $Credentials -Impersonation -Server outlook.office365.com -Verbose
VERBOSE: Loading module C:\Program Files\PackageManagement\NuGet\Packages\Exchange.WebServices.Managed.Api.2.2.1.2\lib\net35\Microsoft.Exchange.WebServices.dll
VERBOSE: Loading module from path ‘C:\Program Files\PackageManagement\NuGet\Packages\Exchange.WebServices.Managed.Api.2.2.1.2\lib\net35\Microsoft.Exchange.WebServices.dll’.
VERBOSE: Module Microsoft.Exchange.WebServices v2.2.1.0 loaded
VERBOSE: Required module Microsoft.Identity.Client.dll could not be located
PS C:\Users\userx\OneDrive\Common Need To Know\PowerShell\Invoke-Unarchive-main>
Please help me in this case
LikeLike
Hi Michel, With your help, i could successfully Unarchive mailboxes of Office 365 and move all data to primary mailboxes. its really a great must have tool..
LikeLike
Glad it was helpful.
LikeLike
Hi Michel! Thanks for your post!
When I try to install Microsoft.Identity.Client always I was constantly getting error of dependency loop: “Install-Package : Dependency loop detected for package ‘Microsoft.Identity.Client'”. Could you help me?
LikeLike
I had that one time with other module, which I needed to forcibly remove (from its folder), reinstall and the necessary restarts. There’s always the option of getting the DLL and putting it in the same folder as the script.
LikeLike
Hello,
I copied the dll into the same folder where the script is located, but I am stll getting an error:
VERBOSE: Module Microsoft.Exchange.WebServices v2.2.1.0 already loaded
VERBOSE: Loading module D:\Master\scripts\EXO\Archive\Microsoft.Identity.Client.dll
VERBOSE: Loading module from path ‘D:\Master\scripts\EXO\Archive\Microsoft.Identity.Client.dll’.
Import-ModuleDLL : Problem loading module Microsoft.Identity.Client: Could not load file or assembly ‘Mono.Android,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065’ or one of its dependencies. The system cannot find
the file specified.
At D:\Master\scripts\EXO\Archive\Invoke-Unarchive.ps1:794 char:5
+ Import-ModuleDLL -Name ‘Microsoft.Identity.Client’ -FileName ‘Mic …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Import-ModuleDLL
Can you help me here? Which DLL copied you to the script folder?
Many Thanks
Michael
LikeLike
Requires 2 modules (or their DLLs): Microsoft.Exchange.WebServices.dll (from the EWS.Managed.Api package) and Microsoft.Identity.Client.dll (from the Microsoft.Identity.Client package) – see https://eightwone.com/2020/10/05/ews-webservices-managed-api/ for installing EWS.Managed.Api, the ADAL module is same process but different name.
LikeLike
Hello,
the Microsoft.Exchange.WebServices v2.2.1.0 is installed, only the Microsoft.Identity.Client reported that error with “Dependency loop detected”. I could instalI it with the command “Install-Package Microsoft.Identity.Client -ProviderName NuGet -skipdependencies” and found in the folder of the package several subfolders with dll files in it. I tried all of them, but I am still getting the error ” Could not load file or assembly ‘Mono.Android”.
Michael
LikeLike
Welcome to packaging – SkipDepencencies just ignores any issues, it does not solve them. Which is why I have the option to look for related DLLs in the script folder. Downloading, unblocking and running the script from elevated prompt (in order to be able to load the modules) usually does the trick.
LikeLike
I copied all dll files to the script folder, but I am still getting the same error. Which version of Microsoft.Identity.Client did you use? I have installed 4.45.
Many Thanks!
LikeLike
No issues with module 4.25 or 4.using PS5.1 and PS7.2.5.
Note it’s not a problem with the script, it’s a problem with module and dependency management.
LikeLike
Hey Michael, will be really great if I understand how to get the “ClientId” value. Call me newbie but I don´t know from where I get that information. My setup is simple: all mailboxes in exchange online and I need to move the archive content back to mailbox to migrate the data to google mailbox and then purge the mailbox content.
LikeLike
For not Azure AD built-in apps and tooling, you need to register an enterprise app. That will generate an Application ID (ClientId). See halfway (‘Now we need to set things up in Azure Active Directory’) through this older but still valid article on this process to the Exchange Online Management module https://eightwone.com/2020/08/05/exchange-online-management-using-exov2-module/
LikeLiked by 1 person
Hi Michel, really great tool here, I was wondering if you knew how I might find out what’s causing this issue: https://i.imgur.com/FW9qy0x.png
This is on-premises Exchange 2013 SP1 and it seems like mailboxes with smaller archives (around 3000 items?) will show no error, or show a few errors and then continue successfully, but larger archives like the one shown just loop the same error forever. I’ve tried adjusting the throttling policy on the server but it doesn’t seem to help so far.
Do you have any suggestions for figuring out what’s going on, or any throttling policy settings that may help? Thanks.
LikeLike
Oh and I forgot to mention, despite what the output is showing, it is actually moving messages from the archive to the primary mailbox, slowly, at about 3-4 messages per second.
LikeLike
The call to move items is asynchronous. When instructing Exchange to move items to folder X, folder X gets sort of locked and you cannot move more items to folder X until the previous move operation has finished. If you took care of throttling, it could be that the operation is resource constraint. The script tries to ease off when it gets told the ServerBusyException (message indicates it is), by adding delays and lowering the batch size (varies from 10 to 50 items per move request). After the request, Exchange can still be busy moving items from archive to mailbox, so then it’s a matter of waiting. Haven’t found a way to speed up this process, if only Managed Folder Assistant could move stuff back as well 🙂
LikeLike
If only there were a way to swap the archive and primary mailboxes temporarily and let MFA do its thing.
LikeLike
Hi Michel
I have client who has 1 year retention but now wants emails moved back and have 2 year retention. What’s the best way of doing this. Current mailbox size is 29GB and archive is 104GB auto expanding. So end goal is main mailbox should have 2 years worth of emails and rest stay in in place archive
LikeLike
Change retention policy, depending on if you made new tags or updated the existing one wait for Managed Folder Assistant to process mailbox, and finally unarchive items younger than X days. That last part is currently not an option of this script, but I put it on the to list since it sounds like a good idea when customers increase the retention time before archiving items.
LikeLike
Hello,
I worked for a long time to get all pre requisites completed for your script and get it working, I got stuck and can’t proceed go ahead of here. Let me know please if I can get any help.
VERBOSE: Module Microsoft.Exchange.WebServices v2.2.1.0 already loaded
VERBOSE: Module Microsoft.Identity.Client v4.24.0.0 already loaded
VERBOSE: Will use provided secret to authenticate
VERBOSE: Authentication token acquired
Processing mailbox ***@******.com (***@******.com)
VERBOSE: Using ***@******.com for impersonation
VERBOSE: Using Exchange Web Services URL https://outlook.office365.com/EWS/Exchange.asmx
WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (403)
Forbidden.”
C:\Users\*****\Desktop\Invoke-Unarchive.ps1 : Cannot access primary mailbox of ***@******.com:
At line:1 char:1
+ .\Invoke-Unarchive.ps1 -Identity ***@******.com -Server outlook …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Invoke-Unarchive.ps1
LikeLiked by 1 person
See if the authentication method you are using in relation to the security principal is allowed (eg BasicAuth) and not blocked by Authentication Policies or Conditional Access. If Modern Authentication is enforced, register an app, provide it required permissions and use TenantId/ClientId and certificate/secret (please no) for authentication. A little write-up on the how-to for that is in the second part of this article: https://eightwone.com/2020/08/05/exchange-online-management-using-exov2-module/
LikeLike
Hi there,
I have set up everything as explained in the guide but I am getting the following PS before the script will run. Both DLL’s load succesfully.
Import-ModuleDLL problem initializing test-object from module microsoft.identitity.client.
Any idea what might be causing this issue?
LikeLike
Still had to propagate changes to fix checking module loading to this script; should be resolved in 1.02.
LikeLike
Keep getting this:
WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “Credentials are required to make a service request.”
Not very clear on how to use a secret with this script – any chance you could clarify how I should form the arguments correctly?
LikeLike
Or I get this one: WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (403) Forbidden.”
My command:
.\Invoke-Unarchive.ps1 -Identity “me@myupn.com” -Server outlook.office365.com -Impersonation -Secret $(ConvertTo-SecureString “client secret value” -AsPlainText -Force) -TenantId “directory-tenant-id” -ClientId “application-client-id” -Verbose
LikeLike
For EXO and OAuth
1) Register an app. Required configuration steps of it are contained in this blog, Exchange.ManageAsApp permissions for EWS should be Office 365 Exchange Online > full_access_as_app : https://eightwone.com/2020/08/05/exchange-online-management-using-exov2-module. Use Secret if you really must, a certificate is better.
2) Use TenantID, Application ID (ClientID) and Secret (or certificate) to authenticate.
3) If authentication fails, make sure things like Conditional Access are not blocking. Use Azure AD portal > Azure Sign-Ins to locate your Application ID and see why is was rejected .
LikeLike
Thanks! I had thought the Exchange.ManageAsApp was the required permission and didn’t see the other full_access_as_app permission – that permission got it working for – really appreciate this script – nice work!
LikeLiked by 1 person
The same with me, Thanks
LikeLike
Hi,
I managed to connect to V3 EXO PowerShell with the -CertificateThumbprint but I am still getting the below error:-
WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote
server returned an error: (403) Forbidden.”
Screenshot of the connection here –> https://onedrive.live.com/?authkey=%21ACL0V%2Du2SQwf2lg&cid=A9FBF65766E40807&id=A9FBF65766E40807%211705&parId=root&o=OneUp
LikeLike
Connecting with thumbprint I get
(line 871) Exception calling “Create” with “1” argument(s): “Confidential Client flows are not available on mobile platforms or on Mac. See https://aka.ms/msal-net-confidential-availability for details.
LikeLike
Great Script!
It would be awesome if you can update this script to work on On-Premise Exchange 2016, and not just Online Exchange only.
LikeLike
No update needed, already works (as mentioned).
LikeLike
Sure no problems, I just assumed it was online only as I was having trouble running this script on my on-premise Exchange 2016 server. I had used your example, but just omitted the “online” parameters since this was a local exchange.
.\Invoke-Unarchive.ps1 -Identity -Verbose
But I got this error
“Parameter set cannot be resolved using the specified named parameters”
So I’m assuming it was expecting those 365 parameters (e.g. -Secret, -TenantID, etc..)
Is there anyway to replace them with local exchange parameters?
LikeLike
For current credentials, use -UseDefaultCredentials, for other credentials, use Credentials
LikeLike
If I just have one mailbox that I’m playing with (testing), can’t I just disable the retention policy, manually move everything from Archive back to Mail Store, disable the archive for that user, then enable the retention policy again? This is a sincere question as I’ve never disabled the retention policy (maybe it’s not even possible…maybe I have to change it from 2 years to 30 years as the default?)
LikeLike
If you disable a retention policy tag (part of policies), not policies themselves. Items flagged with that tag are suspended from processing.
If you set the retention policy for a mailbox to $null, mailbox records management will skip it (naturally, not that Default Retention Policy is by default assigned).
If you assign a different retention policy, that policy will become effective and items will get re-evaluated (personal tags are retained).
If you remove a tag from a policy, items in a mailbox with that policy will still be subject to that tag (expire etc).
If you delete a tag, items that were flagged with that tag (any policy) re-evaluated.
But – you can overall suspend retention also for a mailbox, without reconfiguring any of this, using Set-Mailbox with the RetentionHoldEnabled parameter, which allows you to suspend MRM processing.
LikeLike
Thanks Michel de Rooij for sharing such a lovely script. Would really appreciate if you please let us know the command to be run for Exchange 2016 with basic authentication
LikeLike
Since you are using onprem/basic, invoke-unarchive needs -Credentials $Credential and Server with the hostname/VIP of the Exchange endpoint might also help, bypassing autodiscover.
LikeLike
Script using Credentials parameter
LikeLike
Hey Michael, can you add a feature for specific default folders, like Calendar, Tasks and Notes? Would be great if we could use a switch for a specific folder too.
Thanks!
LikeLike
Noted.
LikeLike
Test, is this working, my last comment is not shown?
LikeLike
We are running the script on an on-prem Exch 2016 server and it seems to be moving everything as expected but we are seeing the following errors in the middle of the run.
Any thoughts to the cause and fix?
———————————————
—ERRORS—
VERBOSE: Collecting folders to unarchive in \
Exception setting “PropertySet”: “Cannot convert the “Microsoft.Exchange.WebServices.Data.PropertySet” value of type
“Microsoft.Exchange.WebServices.Data.PropertySet” to type “Microsoft.Exchange.WebServices.Data.PropertySet”.”
At C:\temp\UnArchive\Invoke-Unarchive.ps1:620 char:9
+ $FolderView.PropertySet= New-Object Microsoft.Exchange.WebSer …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Exception setting “PropertySet”: “Cannot convert the “Microsoft.Exchange.WebServices.Data.PropertySet” value of type
“Microsoft.Exchange.WebServices.Data.PropertySet” to type “Microsoft.Exchange.WebServices.Data.PropertySet”.”
At C:\temp\UnArchive\Invoke-Unarchive.ps1:620 char:9
+ $FolderView.PropertySet= New-Object Microsoft.Exchange.WebSer …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Exception setting “PropertySet”: “Cannot convert the “Microsoft.Exchange.WebServices.Data.PropertySet” value of type
“Microsoft.Exchange.WebServices.Data.PropertySet” to type “Microsoft.Exchange.WebServices.Data.PropertySet”.”
At C:\temp\UnArchive\Invoke-Unarchive.ps1:668 char:9
+ $ItemView.PropertySet= New-Object Microsoft.Exchange.WebServi …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
VERBOSE: Located 4 folders in \
LikeLike
This is just what we need, but struggling with the pre reqs. Got EWS sorted quickly, needed to place the DLL for Microsoft.Identity.Client in the script folder…but I cant get past this new error. I placed the DLL for this in the script folder, but to no avail….tried this on 2 clients, but get the same….
Any ideas?
—-
VERBOSE: Module Microsoft.Exchange.WebServices v2.2.1.0 already loadedVERBOSE: Module Microsoft.Identity.Client v4.53.0.0 already loadedVERBOSE: Will use provided secret to authenticateException calling “Create” with “1” argument(s): “Could not load file or assembly ‘Microsoft.IdentityModel.Abstractions, Version=6.22.0.0, Culture=neutral, P
LikeLike
Hey,
did you ever manage to fix that Problem?
I tried it on 4 Clients with different Windows and PS Versions. Cannot seem to get it to work…
Best Wishes
LikeLike
Hi,
For me the script works in like 50% of the cases.
When I run in to an error i almost always get this error:
Folder Archive in personal archive is empty
Archive is a non-removable Distinguished Folder, skipping deletion
Folder Calendario exists, merging contents to unarchive 16 item(s) and 0 folder(s)
VERBOSE: Collecting folders to unarchive in Calendario
VERBOSE: Retrieving items to unarchive from Calendario ..
VERBOSE: Discovered 16 items in Calendario
VERBOSE: Unarchiving 16/16 item(s) from Calendario
VERBOSE: Located 0 folders in Calendario
Folder Calendario in personal archive is empty
Folder Calendario in personal archive has been removed
Unarchiving folder Deleted Items
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 0s
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 0s
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 0s
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 1s
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 1s
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 1s
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 2s
WARNING: EWS operation () failed, will retry later
WARNING: Previous EWS operation failed, waiting for 3s
After this error I can let it run for hours … it never recovers from it.
Anyone any idea what might cause this?
Anyway Thx for this wonderful scrip Michel!
LikeLike
The operation is heavily throttled; you might request temporary removal of EWS throttling:
Support > New service requests > Run diagnostics > Select 30, 60 or 90 days > Update Settings
As soon as Graph reaches parity level with EWS, I can work on a Graph version
LikeLike
We already did the Remove Throttling request, still 150MB/ 5min. is the maximum allowed by Microsoft.
With 500 mailboxes (3.5TB in total) to “Unarchive” it is taking a long time.
What seems to help is when we get the “WARNING: EWS operation () failed, will retry later” error. Just close the full terminal window and start a new one. Usually it gets going again for some time (for larger archives we sometimes needs to repeat this multiple times)
LikeLike
OK. For your idea what is taking a long time: when unarchiving, we collect items to unarchive. Per batch of X items, we send the back-end the instruction to move these items (in batches) from the archive to the mailbox. This single call is asynchronous, so we can do a few but at some point the back-end will tell us to back off. Meanwhile, items get moved and no further operation will be permitted on the folder (locked). Now, playing with the max. number of items to move, inserting micro-pauses helps overall, but it won’t perform magic. Now if only Exchange Online offered a call to unarchive or reverse retention .. it is what is is. Eventually, it gets there.
LikeLike
Thx for the feedback! This script is helping us out big time! So thanks for the hard work!
LikeLike
Sorry a bit new to this. I created an app registration in Azure, copied the tenant ID, AppID, and secret, added to the relevant parts of the command but get the following error message.
Invoke-Unarchive.ps1 : Cannot process argument transformation on parameter ‘Secret’. Cannot convert the
“007f5229-0a31-4e82-8b43-0b65d4858fb8” value of type “System.String” to type “System.Security.SecureString”.
Without them I get the following error message>
Invoke-Unarchive.ps1 : Cannot bind argument to parameter ‘Secret’ because it is null.
What am I doing wrong?
LikeLike
Try this:
$Secret = “<client-id>”
$SecureSecret = ConvertTo-SecureString -String $secret -asplaintext -force
and then use the $SecureSecret in the command.
LikeLike
Hi, not sure how cold this post is but I’m trying to use your Script and getting an error about Microsoft.IdentityModel.Abstractions which I tried to install manually after receiving the error but I am still getting this error.
I was having difficulty installing Microsoft.Identity.Client before but apparently resolved that by deleting, rebooting and reinstalling. This has not worked for this module. Any insights?
Also for some reason the Microsoft.Identity.Client module appears as System.Obj[] when loaded.
Thanks
LikeLike
The System.Object[]: Sounds you have 2 versions (can be the same version but from different path) of the module Microsoft.Identity.Client loaded.
To avoid this dependency annoyance, you could try copying the Microsoft.Identity.Client.dll from where the package is installed to the folder where the script resides. Unload it (Remove-Module Microsoft.Identity.Client) and retry. Note the script does not unload the module when it has the module loaded, to speed up things when it is called multiple times going through identities for example.
LikeLike
This is extremely useful! It would be nice if they had built a method to fold the archive back into the primary mailbox out of the box, but what can you do? I have used this a couple of times now and it seems to work well, though it does take a while.
At what point do I turn off the archive setting from EAC under the users mailbox? I was curious that if I run the script first, would it start archiving again when done? If I disable the archive first, what happens to the archive data? Is it lost? Would the script still be able to access it to merge the items back?
LikeLike
It is indeed odd, and confusion since I still see people confused with the ‘archive’ button not doing what people expect. Note that if you disable archive, it will be inaccessible. When you move items back, and there are retention & archiving policies in place, stuff will be moved again when the Managed Folder Agent kicks in. So, remove those retention tags from the policy or assign another policy without those (note that $null with set it to the default RP).
LikeLike
Hello Michel. During During execution of script I got an error e.g. :
Unarchiving folder ArchiveMISCELLANEOUS
WARNING: Error performing operation MoveFolder on MISCELLANEOUS. Error: The move or copy operation failed.
Where I need to dig ?
LikeLike
Any additional reporting when you add -Verbose ?
LikeLike
Hello Michael. When I try to move this folder manually in Outlook I`ve got a message : “Cannot copy this folder because it may contain private items” . I checked all settings and I cant find any private flags or attribute.
LikeLike
You should be able to circumvent this situation by using impersonation. That said, when using the script against Exchange Online with OAuth, impersonation is always on. For Exchange on-premises, you need to explicitly configure Application-Impersonation permissions for the account you use/have to be able to work with private items. (long overdue as I am currently going through the backlogs)
LikeLike
Hello Michael. When I try to move this folder manually in Outlook I`ve got a message : “Cannot copy this folder because it may contain private items” . I checked all settings and I cant find any private flags or attribute.
LikeLike
Hello, Thank you for your article I am using your solution and I have a small problem when I want to unarchive a folder that does not exist in my mailbox, it takes the name of its parent instead of its own but no problem for its subdirectories.
Here are 2 examples:
In-place Archive -> Folder1 -> Subfolder1
In-place Archive -> Archive -> Folder2 -> Subfolder2
Results :
Folders -> Top of information Store -> Subfolder1
Folders -> Archive -> Archive -> Subfolder2
Do you have any idea where this is coming from?
LikeLike
No, thanks for the report – I’ll add it to the issuelist
LikeLike
Hey there,
i still cannot find a way to get around the Microsoft.IdentityModel.Abstraction Error when using an EnterpriseApp to access the Mailbox.
“Ausnahme beim Abrufen des Elements “WithClientSecret”: “Die Datei oder Assembly “Microsoft.IdentityModel.Abstractions, Version=6.35.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”
oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.”
Also when using the actual Mailbox of the User I do get an 401 No Permission. Do i need to give that specific User any Role if I use his credentials?
Thank you for your awesome work!
LikeLike
Firstly, install Microsoft.IdentityModel.Abstractions 6.35 like so:
Install-Package Microsoft.IdentityModel.Abstractions -RequiredVersion 6.35 -ProviderName NuGet
Then import it before running the script, like so:
Import-ModuleDLL -Name ‘Microsoft.IdentityModel.Abstractions’ -FileName ‘Microsoft.IdentityModel.Abstractions.dll’ -Package ‘Microsoft.IdentityModel.Abstractions’
Now run the script.
As for permissions, it might be that you need to give your Oauth App the Exchange.ManageAsApp from “APIs my organization uses”, then Office 365 Exchange Online
LikeLike
Hello! First of all thank you for the work put into this script, it’s going to be a live saver for us. I did have a question: when running the script I get the following error on line 887 of the script:
VERBOSE: Unarchiving 229 of 2437 item(s) from inboxMethod invocation failed because [Microsoft.Exchange.WebServices.Data.ItemId] does not contain a method named ‘Clear’.At C:Users<username>DesktopunarchiveInvoke-Unarchive.ps1:887 char:37
If I comment out this line the script appears to run correcty, moving one mail item at a time. I’m using Microsoft.Exchange.WebServices.dll version 2.2.1.0 placed in the same directory as the script.
Any ideas?
LikeLike
When I run this, I get the following:
VERBOSE: Loading assembly C:\path\to\Microsoft.Exchange.WebServices.dll
VERBOSE: Loading assembly C:\path\to\Microsoft.Identity.Client.dll
VERBOSE: Assembly Microsoft.Identity.Client loading issue:Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
I’m running the latest version of all required dependencies.
LikeLike