Created
December 18, 2025 15:54
-
-
Save trossr32/a21536449c4941392d972e189172b5d4 to your computer and use it in GitHub Desktop.
Scans a .NET solution for NuGet package versions used across projects.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Nuget-SolutionPackageVersions { | |
| <# | |
| .SYNOPSIS | |
| Scans a .NET solution for NuGet package versions used across projects. | |
| .DESCRIPTION | |
| Scans a .NET solution for NuGet package versions used across projects. | |
| .PARAMETER SolutionPath | |
| The path to the .NET solution (.sln file). If not provided, the current directory is used. | |
| .EXAMPLE | |
| Nuget-SolutionPackageVersions -SolutionPath "C:\Projects\MySolution" | |
| Scans the specified solution for NuGet package versions. | |
| .EXAMPLE | |
| Nuget-SolutionPackageVersions | |
| Scans the current directory for NuGet package versions. | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory=$false, ValueFromPipeline=$true)] | |
| [string]$SolutionPath | |
| ) | |
| begin { | |
| # if solution path not provided, use current directory | |
| if (-not $SolutionPath) { | |
| $SolutionPath = Get-Location | |
| } | |
| # Check there's a .sln file in the provided path | |
| $slnFiles = Get-ChildItem -Path $SolutionPath -Filter *.sln | |
| if ($slnFiles.Count -eq 0) { | |
| throw "No .sln file found in path: $SolutionPath" | |
| } | |
| # check there's at least one .csproj file in the provided path or subdirectories | |
| $csprojFiles = Get-ChildItem -Path $SolutionPath -Filter *.csproj -Recurse | |
| if ($csprojFiles.Count -eq 0) { | |
| throw "No .csproj file(s) found in path: $SolutionPath" | |
| } | |
| } | |
| process { | |
| # Scan all .csproj files and aggregate unique package versions | |
| $packages = Get-ChildItem -Filter *.csproj -Recurse | | |
| Get-Content | | |
| Select-String -Pattern '<PackageReference Include="([^"]+)" Version="([^"]+)"' -AllMatches | | |
| ForEach-Object { $_.Matches } | | |
| Group-Object { $_.Groups[1].Value } | | |
| ForEach-Object { @{ | |
| Name = $_.Name | |
| Versions = $_.Group.ForEach({ $_.Groups[2].Value }) | Select-Object -Unique | |
| }} | |
| # Build table rows: Package | Versions (comma-delimited) | Status (emoji) | |
| $rows = $packages | | |
| Sort-Object { $_.Name } | | |
| ForEach-Object { | |
| $versionList = ($_.Versions -join ', ') | |
| $statusEmoji = if ($_.Versions.Count -le 1) { "✅" } else { "❌" } | |
| [pscustomobject]@{ | |
| Package = $_.Name | |
| Versions = $versionList | |
| "No consolidation required" = $statusEmoji | |
| } | |
| } | |
| # Display as a formatted table | |
| $rows | Format-Table -AutoSize | |
| } | |
| end { | |
| Write-Host "" | |
| Write-Host "Create a Directory.Packages.props file using: " -NoNewline | |
| Write-Host "dotnet new packagesprops" -ForegroundColor Magenta | |
| Write-Host "" | |
| Write-Host "Automate migration to Central Package Management (CPM) using: " | |
| Write-Host "Install if not present => " -NoNewline | |
| Write-Host "dotnet tool install CentralisedPackageConverter --global" -ForegroundColor Magenta | |
| Write-Host "Convert solution to CPM => " -NoNewline | |
| Write-Host "central-pkg-converter '$SolutionPath'" -ForegroundColor Magenta | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment