Microsoft is retiring Project Online on September 30, 2026, and after that date the projects living in your Project Web App instance simply will not be reachable anymore. If you want to keep that history, you need to back up Project Online projects to local storage — or park them somewhere in SharePoint to open later — before the lights go out. I went looking for a clean export-everything button, did not find one, and ended up with a half-automated PowerShell approach instead. It is not pretty, but it is a lot faster than opening and saving every project by hand.
Key Takeaways
- Project Online retires on September 30, 2026; after that you lose access to the projects and their data, so backing them up beforehand is not optional if you want to keep the history.
- You can pull the full list of projects from the ProjectData OData API at
/_api/ProjectData/Projectswhile authenticated as a Project Web App administrator. - PowerShell parses the saved OData XML into a list of project names you can iterate over.
- The Project Professional desktop client (installed on the machine running the script) does the actual export, opening each project read-only and saving it as a local
.mppfile through COM automation. - Suppressing the client's link and security prompts with
DisplayAlertsandAutomationSecuritydid not work for me, so the process is semi-automated — you still click through dialogs — but it beats doing every project manually.
Environment
- Project Online tenant with a Project Web App (PWA) site at
https://<tenant>.sharepoint.com/sites/pwa. - An account in the Administrators (or Portfolio Managers / Portfolio Viewers) group — required to read the OData feed.
- Microsoft Project Professional (2019/2021/Microsoft 365 Apps desktop client) installed locally, with a configured Project Web App account so it can open server projects by name.
- Windows 11, Windows PowerShell 5.1.
- A local output folder with enough space for one
.mppper project.
The Problem
Project Online has been on borrowed time for a while, and Microsoft has now put a hard date on it. The official retirement announcement spells it out: end of sale was October 1, 2025, new tenant creation stops April 1, 2026, and the service itself goes dark on September 30, 2026. The desktop Project client is not affected — only the online service and its PWA data. That last part is the catch. Anything that only exists in PWA, including the project schedules themselves, has to come out before the deadline.
My first instinct was to look for a bulk export. There isn't one. The PWA interface lets you open a project and save it locally one at a time, which is fine for five projects and miserable for a few hundred. Microsoft's guidance is essentially "back up your data and migrate to Planner or Project Server Subscription Edition," which is sound advice that conveniently skips over the tedious part: actually getting hundreds of schedules onto a disk in a format you can still open in 2027.
So the goal narrowed to something concrete: produce one .mpp file per project, locally, with the original project name, without clicking through the PWA project center several hundred times. Two pieces are needed for that — a list of every project, and something that can open and save each one. The list comes from the reporting API; the saving comes from the desktop client driven by PowerShell.
The Solution
Step 1 — Pull the project list from the ProjectData OData API
Project Online exposes its reporting data through the ProjectData OData service. The service root is https://<tenant>.sharepoint.com/sites/pwa/_api/ProjectData/, and the collection I care about is Projects. Browsing to the feed in a browser while signed in as a Project admin returns the whole list as Atom/OData XML:
https://.sharepoint.com/sites/pwa/_api/ProjectData/Projects
Worth knowing before you try this: not every PWA user can read the feed. In the default SharePoint permission mode, only members of the Administrators, Portfolio Managers, and Portfolio Viewers groups have access to the OData service. I authenticated as a Project administrator, let the page render the full XML, and saved it to disk (Ctrl+S) as ProjectData.xml. If you want to see the shape of the data first, the /_api/ProjectData/$metadata endpoint returns the entity model. Microsoft's ProjectData OData service reference documents the Projects entity set and its fields, including ProjectName.
Copying the XML by hand is the least elegant step in the whole thing. You could absolutely script the fetch with Invoke-RestMethod and the right authentication, but for a one-off migration I did not want to fight modern-auth token handling for an API that is being switched off in a few months. Saving the rendered feed to a file took ten seconds and let me move on.
Step 2 — Parse the project names with PowerShell
The OData feed is namespaced XML — project properties live in the Microsoft dataservices namespace — so a plain $xml.feed.entry... walk can be brittle. Select-Xml with the namespaces declared is more reliable. Load the file and pull every ProjectName:
[xml]$xml = Get-Content -Path 'C:\Export\ProjectData.xml' -Raw
$ns = @{
d = 'http://schemas.microsoft.com/ado/2007/08/dataservices'
m = 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'
}
$projects = Select-Xml -Xml $xml -Namespace $ns -XPath '//d:ProjectName' |
ForEach-Object {
[pscustomobject]@{ ProjectName = $_.Node.InnerText }
} |
Where-Object { $_.ProjectName } # drop empties / template entries
Write-Host "Found $($projects.Count) projects to export"
That gives a clean list of objects with a ProjectName property, which is all the export loop needs. If you would rather work with the data in a spreadsheet first — to sanity-check counts or filter out archived projects — piping $projects to Export-Csv is the obvious move; I cover that pattern in PowerShell Quick Guide: Exporting Data to CSV Files.
Step 3 — Open and save each project as a local .mpp file
This is where the Project Professional desktop client comes in. It has to be installed on the machine running the script — there is no server-side way to produce an .mpp — and it must be signed in to a Project Web App account so that opening a project by name resolves against the server rather than the local file system. With that in place, PowerShell talks to it through the MSProject.Application COM object.
The export itself is a loop: open each project read-only, save it to the output folder as .mpp, close without saving back to the server. Project names can contain characters that are illegal in file names, so I strip those first:
$OutPath = 'C:\Export\mpp'
New-Item -ItemType Directory -Path $OutPath -Force | Out-Null
$app = New-Object -ComObject MSProject.Application
$app.Visible = $true # see what it is doing; also needed to click prompts
$saved = 0
$failed = 0
foreach ($p in $projects) {
$name = $p.ProjectName
$safe = $name -replace '[\\/:*?"<>|]', '-'
$file = Join-Path $OutPath "$safe.mpp"
try {
$app.FileOpen($name, $true) # read-only, no checkout
$app.FileSaveAs($file)
$app.FileClose(0) # pjDoNotSave
$saved++
Write-Host " OK - $name"
}
catch {
Write-Warning " FAILED - $name - $_"
try { $app.FileClose(0) } catch { }
$failed++
}
}
Write-Host "Done. Saved $saved, failed $failed."
A few notes on the specifics. The $true on FileOpen opens read-only and avoids a checkout, which is what you want for a backup — you are not editing anything. FileClose(0) passes pjDoNotSave so the client never writes back to PWA. The try/catch matters more than it looks: a single project that refuses to open will otherwise leave the client sitting on a modal dialog and stall the whole run, so the catch closes whatever is open and moves on, tallying failures to revisit by hand.
The disclaimer: it is only half automated
Here is the honest part. I wanted this to be hands-off, and it is not. Project Professional throws interactive prompts that I could not get to stay quiet — most commonly the prompt about cross-project links when a schedule links to other projects, and the client's own security and connection dialogs. I tried the two suppression switches you would reach for first: setting DisplayAlerts to $false and AutomationSecurity to 3 (msoAutomationSecurityForceDisable) before each open, then restoring them afterwards. The original value is captured once before the loop with $origSecurity = $app.AutomationSecurity:
try {
$app.DisplayAlerts = $false
$app.AutomationSecurity = 3 # msoAutomationSecurityForceDisable
$app.FileOpen($name, $true) # read-only, no checkout
$app.FileSaveAs($file)
$app.FileClose(0) # pjDoNotSave
}
finally {
$app.DisplayAlerts = $true
$app.AutomationSecurity = $origSecurity
}
Neither setting stopped the prompts in my environment. The assignments themselves ran without error — so both properties exist and are accepted on the Project application object — but the cross-project link prompt and the security and connection dialogs still appeared and still waited for a click. They are evidently raised by the client itself, below the layer those two switches control, rather than as the standard automation alerts that DisplayAlerts is meant to handle.
The practical consequence is that you have to babysit the run and click through dialogs as they appear. That is why the client is set to Visible = $true — you need to see and dismiss the prompts. It is annoying, but it is still far faster than navigating PWA and saving each project manually, and the loop handles the file naming, the read-only open, and the failure tracking for you. If anyone has reliably silenced these specific prompts, I would genuinely like to know, because the rest of this would otherwise be a clean unattended job.
Once the run finishes, you have a folder of .mpp files named after the original projects. Those open in any Project desktop client, which is unaffected by the retirement, so they remain usable long after the online service is gone. If you would rather keep them accessible to a team, dropping the folder into a SharePoint document library works fine — the files open locally from there.
Frequently Asked Questions
What permissions do I need to read the ProjectData OData feed?
In the default SharePoint permission mode, only members of the Administrators, Portfolio Managers, or Portfolio Viewers groups can query the ProjectData service. I ran it as a Project Web App administrator. A standard team member account will typically get an access-denied response instead of the feed.
Can I back up Project Online projects without Project Professional?
Not into .mpp format. The .mpp file is produced by the Project desktop client, so it has to be installed on the machine doing the export. You can pull task and assignment data as XML or CSV straight from the OData feed for reporting purposes, but that is not the same as a restorable project schedule.
Will the exported .mpp files still open after September 30, 2026?
Yes. The retirement applies to the Project Online service and its PWA data, not to the desktop application. Project desktop remains available, so the .mpp files you save now will continue to open normally after the online service is gone.
Why could the Project Professional prompts not be suppressed?
I tried both DisplayAlerts = $false and AutomationSecurity = 3 (force-disable) before each open. Neither stopped the cross-project link prompt or the client's security and connection dialogs in my environment. Those dialogs are raised by the client itself, below the layer those two switches control, so the script cannot dismiss them programmatically and you end up clicking through them manually.
Is querying a service that is being retired even worth scripting?
For a one-time migration, yes — the OData feed is the quickest read-only way to enumerate every project, and you only have to do it once. I deliberately did not invest in robust modern-auth token handling for a service with a few months left; saving the rendered feed to a file was good enough to drive the rest of the process.
Conclusion
Should Microsoft ship a one-click "export every project before we delete them" button when they retire a service that organizations have trusted with a decade of project data? Probably. But here we are, stitching together an OData feed, a bit of XML parsing, and COM automation to do what amounts to a glorified bulk Save As.
The result is not fully unattended, and the popups are a real nuisance, but it works: a folder of cleanly named .mpp files, one per project, produced in a fraction of the time the fully manual route would take. If you are sitting on a Project Online tenant, the deadline is fixed and it is not far off. Pull the list, run the loop, click through the dialogs, and get your projects onto disk while you still can.
Related Posts
- PowerShell Quick Guide: Exporting Data to CSV Files — the export pattern I used to sanity-check the parsed project list before running the loop.
- PowerShell Quick Guide: Creating Your First Security Audit Script — a starting point if you are new to building practical scripts like this one.
- PowerShell Quick Guide: Remote Management Basics — useful if you want to drive the export from a dedicated admin workstation.
Editorial note: posts on this blog are drafted with AI assistance and then reviewed, edited, and tested against a real environment before publishing. Commands, output, and screenshots come from systems I actually ran the work on.
0 comments:
Post a Comment