

Moving sites to cold storage is a very relevant topic these days. For many companies the amount of data stored in SharePoint has quickly grown beyond the storage quota included with Microsoft 365 licenses. Growing beyond that means higher storage costs. Archiving sites that aren’t actively used is a way to help get the costs down. This post highlights the various means I found to archive SharePoint sites programmatically with Microsoft 365 Archive.
A note on authorization
Setting up auth is outside of the scope of this post, but you’ll need to think about the following when executing any of the code examples below:
When running in the context of a signed in user you’ll need an Entra application with delegated AllSites.FullControl
permissions on the SharePoint resource. The signed in user needs to have the SharePoint administrator (or Global administrator) role.
When running in the context of an application (Also called app only or workload identity), you’ll need the rather heavy Application permission scope Sites.FullControl.All
on the SharePoint resource, because you’ll be working with the tenant administration site.
Using the Client Side Object Model (CSOM)
When using a .NET app to archive SharePoint sites, we can use CSOM through the nuget package “Microsoft.SharePointOnline.CSOM”. (Or for example the open source package “PnP.Framework”.)
Using the following code you’ll be able to archive sites:
// You require the following using statement.
using Microsoft.Online.SharePoint.TenantAdministration;
// You'll need to create a ClientContext based on the tenant administration site.
// This is outside of the scope of this post, but for example:
// var authManager = new PnP.Framework.AuthenticationManager(<some parameters>);
// using var clientContext = authManager.GetContext("https://contoso-admin.sharepoint.com");
var tenant = new Tenant(clientContext);
var operation = tenant.ArchiveSiteByUrl("https://contoso.sharepoint.com/sites/sales");
clientContext.Load(operation, i => i.IsComplete);
clientContext.ExecuteQuery();
// The following is really only needed if you want to make sure the code waits for the completion of the operation.
while (!operation.IsComplete)
{
System.Threading.Thread.Sleep(1000);
operation.RefreshLoad();
clientContext.ExecuteQuery();
}
In my tests, sites were almost instantly archived, which means we could also skip polling for the completion of the operation. However, with larger sites containing actual data it could potentially take longer, so I’ve included the example anyway.
Alternative methods that can be used are UnarchiveSiteByUrl
, ArchiveSiteById
and UnarchiveSiteById
. With the last two you’ll need the SharePoint Site ID, which is a GUID that can be retrieved from the Site object.
Using the SharePoint REST API
You can also use the SharePoint REST API. However, this is not an API that’s officially supported for public use, so don’t come calling me when the endpoint changes 😅.
The HTTP call to archive the site is quite simple:
POST https://contoso-admin.sharepoint.com/_api/Microsoft_Online_SharePoint_TenantAdministration_Tenant/ArchiveSiteById('112132a9-0ad3-4b53-ab54-9707108ac685')
Unarchiving the site is as easy:
POST https://contoso-admin.sharepoint.com/_api/Microsoft_Online_SharePoint_TenantAdministration_Tenant/UnarchiveSiteById('112132a9-0ad3-4b53-ab54-9707108ac685')
Of course the GUID that is used in the examples is just a dummy GUID. On this API you’ll need the Site Id, which you can get by calling the following endpoint on the site that you want to archive: /_api/site?$select=Id
.
The endpoints return an SpoOperation JSON object, just like the CSOM variants do. I did not do research into how to poll those for completion of the operation though.
❗ There’s currently no endpoint to archive sites by URL.
Using the CLI for Microsoft 365
You can use scripting for automation purposes as well. For example using the CLI for Microsoft 365, which is a popular open source commandline tool for managing your Microsoft 365 Tenant. This tool can also be run in Azure Functions, bringing timely executed automation operations within your grasp.
Archiving and unarchiving sites can be done as follows:
m365 spo tenant site archive --url "https://contoso.sharepoint.com/sites/sales" --force
m365 spo tenant site unarchive --url "https://contoso.sharepoint.com/sites/sales" --force
Using PnP PowerShell
Of course, PnP PowerShell needs to be mentioned here as well, as another popular tool for managing your Microsoft 365 Tenant. PnP PowerShell can be easily incorporated in PowerShell scripts running in the cloud, like Azure Automation Runbooks or Azure Functions.
Archiving and Reactivating sites using PnP PowerShell can be done as follows:
Set-PnPSiteArchiveState "https://contoso.sharepoint.com/sites/sales" -ArchiveState Archived -Force
Set-PnPSiteArchiveState "https://contoso.sharepoint.com/sites/sales" -ArchiveState Active -Force
Using SPO PowerShell
Using PowerShell scripting with Microsofts own PowerShell tooling is of course available as well, using the following script.
Archiving and Reactivating sites using PnP PowerShell can be done as follows:
Set-SPOSiteArchiveState "https://contoso.sharepoint.com/sites/sales" -ArchiveState Archived -Confirm
Set-SPOSiteArchiveState "https://contoso.sharepoint.com/sites/sales" -ArchiveState Active -Confirm
Conclusion
Archiving and reactivating sites with Microsoft 365 Archive is actually quite easy. I’m hoping the examples will help you get started quickly! If you’ve got any questions, do drop me a DM!
🚀 Happy coding!!
Sources
- Microsoft docs - Microsoft 365 Archive
- CLI for Microsoft 365 - Archiving a site
- CLI for Microsoft 365 - Unarchiving a site
- PnP PowerShell - Archiving a site
- Microsoft docs - Archiving a site using SPO PowerShell
sharepoint m365-archive
Support me by sharing this
More
More blogs

Updating and using the property bag in 2024
It's an old, but useful feature, and impacted by the change Microsoft is pushing with NoScript sites. Or is it? Here's how to use the property bag in 2024.
Read more
Extending Microsoft 365 with custom retention controls - Part 2
New release of a small Microsoft 365 extension I've developed to view & manage retention controls.
Read more
SPFx and the potential pitfall of partial page navigation
How you need to take partial page navigation into account when building SPFx customizations.
Read moreThanks
Thanks for reading

Thanks for reading my blog, I hope you got what you came for. Blogs of others have been super important during my work. This site is me returning the favor. If you read anything you do not understand because I failed to clarify it enough, please drop me a post using my socials.
Warm regards,
Martin
Microsoft MVP | Microsoft 365 Architect