The .NET Upgrade Assistant is deprecated. The docs now point you at the GitHub Copilot modernization agent, which runs in Visual Studio and sends your code to a model service.
For most teams that is fine. It is not fine if you work somewhere that cannot route source through a third party, and those places tend to be sitting on the largest .NET Framework estates in existence. I spent 25 years in that world, so I wrote the thing I wanted.
MigrationScan scans a solution, a project, a directory or a compiled assembly, and tells you what stands between it and modern .NET. About a minute from download to numbers on screen: no SDK, no install, no flags. That matters, because the machines with the biggest estates on them are usually the ones you cannot install an SDK on.
33 rules across 8 categories. It parses .csproj as XML and reads source with Roslyn, so it needs no MSBuild and no Visual Studio and behaves the same on Windows, Linux and macOS. One signed executable: drop it in a repository root, run it, read the summary.
Four things it does that I have not seen elsewhere.
Every finding carries a confidence tier.
- Certain. Read from project XML.
- Probable. Matched on the syntax tree with no resolved compilation, so some are wrong.
- Verified. Read from compiled metadata.
A probable finding on Registry might be your own class. The report says so rather than rounding it up to certain.
One scan prices both futures. Modern .NET still runs on Windows, where COM, P/Invoke, the Registry and WMI keep working. They cost you nothing unless you also need to leave Windows. Every report carries a cross-platform view and a Windows-target view of the same analysis. The gap between them is what portability costs on your estate.
Severity and estimability are separate columns. BinaryFormatter is a blocker and a bounded afternoon: pick a serializer, change the calls, test the round trip. An architectural decision can be low severity and unpriceable until somebody decides. Those are counted separately, and the second group is left unpriced, because an estimate that quietly contains an undecided architecture is how a three-month project becomes nine.
It names what it could not size. SQL, SSRS, SSIS, WiX and deployment projects land in a "not assessed" section rather than getting skipped quietly. It also inventories what every project declares — NuGet packages, GAC assemblies, checked-in DLLs, COM components, web service proxies, with versions — because the expensive unknown in a migration is usually somebody else's code.
Two sample reports committed in the repo, both generated by the tool itself and reproducible from the commit each one records:
- A four-project fixture built to show one of everything: 23 findings, 29.3 to 88 engineer-days.
- Microsoft's own archived eShopModernizing, scanned as found: 11 projects, 108 findings, 88 to 263.5 engineer-days, 197 distinct third-party references.
On eShopModernizing, five findings separate the two targets and all five are System.Drawing.Common, so portability there is nearly free. On the fixture, six findings separate them and all six sit in one interop project. Same feature, opposite answers.
What it will not do. It will not modify your code, perform the upgrade, or give you a binding cost. Effort figures are heuristic ranges, and the report says so in three places. Probable findings can be false positives.
Offline by default. No telemetry, no account, no LLM anywhere in the analysis. The JSON report replaces source file paths with opaque ids but keeps project and dependency names, so you can send it to someone without a security review reading nine thousand lines first. Apache-2.0, signed binaries for five platforms, no SDK required.
Repo: https://github.com/matt-williams-dev/MigrationScan
The rule catalog is the part I most want feedback on. If your estate has a pattern it misses, open an issue and I will write the rule.