Last active
January 9, 2026 20:09
-
-
Save Wind010/db6e883efa7a6c2d824514efeebd3b85 to your computer and use it in GitHub Desktop.
This script updates the versions of specified NuGet packages in a Directory.Packages.props file to a new version, which can be provided or fetched as the latest from NuGet/Artificatory.
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
| # Update-Packages.ps1 | |
| # This script updates the versions of specified NuGet packages in a Directory.Packages.props file | |
| # to a new version, which can be provided or fetched as the latest from NuGet/Artificatory. | |
| param( | |
| [Parameter(Mandatory=$false)] | |
| [string]$NewVersion = $null, | |
| [Parameter(Mandatory=$false)] | |
| [string[]]$PackagePrefixes = @("Some.Package.One" | |
| , "Some.Package.Two"), | |
| [Parameter(Mandatory=$false)] | |
| [string]$FilePath = "Directory.Packages.props", | |
| [Parameter(Mandatory=$false)] | |
| [bool]$IsDebug = $false | |
| ) | |
| $ErrorActionPreference = "Stop" | |
| if (-not (Test-Path -Path $FilePath)) { | |
| throw "File not found: $FilePath" | |
| } | |
| function Get-BranchPrefix { | |
| Write-Host "Determining current git branch..." -ForegroundColor Cyan | |
| $branchName = git rev-parse --abbrev-ref HEAD 2>$null | |
| if ($null -eq $branchName -or $branchName -eq "") { | |
| Write-Warning "Unable to determine git branch name. No branch filtering will be applied." | |
| return $null | |
| } | |
| Write-Host "Current branch: $branchName" -ForegroundColor Yellow | |
| # Extract prefix (e.g., "DFP-0000" from "DFP-0000-SomeStory"). Update as needed or not use. | |
| $pattern = '^([A-Za-z]+-\d+)' | |
| if ($branchName -match $pattern) { | |
| $prefix = $matches[1] | |
| Write-Host "Branch prefix extracted: $prefix" -ForegroundColor Green | |
| return $prefix | |
| } | |
| Write-Warning "Branch name '$branchName' does not match expected pattern (e.g., $pattern). No branch filtering will be applied." | |
| return $null | |
| } | |
| function Get-LatestPackageVersion { | |
| param( | |
| [string]$PackageName, | |
| [string]$BranchPrefix = $null | |
| ) | |
| Write-Host "Determining latest version of $PackageName from NuGet..." -ForegroundColor Cyan | |
| # The 1st result is the most accurate. The returned results is a list of packages matching the search | |
| # and is the only the latest version. | |
| $packageInfo = dotnet package search $PackageName --prerelease --take 1 --format json | ConvertFrom-Json | |
| if ($null -eq $packageInfo -or $null -eq $packageInfo.searchResult.packages) { | |
| Write-Error "Failed to retrieve packages for $PackageName from NuGet." | |
| return $null | |
| } | |
| $packages = $packageInfo.searchResult.packages | |
| if ($IsDebug) { | |
| Write-Host "Debug: Found $($packages.Count) package(s)" -ForegroundColor Magenta | |
| foreach ($pkg in $packages) { | |
| Write-Host " - $($pkg.id) : $($pkg.latestVersion)" -ForegroundColor Magenta | |
| } | |
| } | |
| # Find the package that contains name | |
| $targetPackage = $packages | Where-Object { $_.id -like "*$PackageName*" } | Select-Object -First 1 | |
| if ($null -eq $targetPackage) { | |
| Write-Error "Package $PackageName not found in search results." | |
| return $null | |
| } | |
| # If we have a branch prefix, filter versions | |
| if (![string]::IsNullOrEmpty($BranchPrefix)) { | |
| Write-Host "Filtering for versions starting with '$BranchPrefix'..." -ForegroundColor Cyan | |
| # Get all versions for this package | |
| $allVersionsJson = dotnet package show $PackageName --prerelease --format json 2>$null | |
| if ($null -eq $allVersionsJson -or $allVersionsJson -eq "") { | |
| Write-Warning "Could not retrieve version list for $PackageName. Using latest version without filtering." | |
| $latestVersion = $targetPackage.latestVersion | |
| } else { | |
| $packageInfo = $allVersionsJson | ConvertFrom-Json | |
| if ($null -ne $packageInfo.versions -and $packageInfo.versions.Count -gt 0) { | |
| # Filter versions that start with the branch prefix | |
| $filteredVersions = $packageInfo.versions | Where-Object { $_ -like "$BranchPrefix*" } | |
| if ($IsDebug -and $null -ne $filteredVersions) { | |
| Write-Host "Debug: Filtered versions:" -ForegroundColor Magenta | |
| $filteredVersions | ForEach-Object { Write-Host " - $_" -ForegroundColor Magenta } | |
| } | |
| if ($null -ne $filteredVersions -and $filteredVersions.Count -gt 0) { | |
| # Get the latest filtered version (versions are typically returned in descending order) | |
| $latestVersion = $filteredVersions | Select-Object -First 1 | |
| Write-Host "Found branch-specific version: $latestVersion" -ForegroundColor Green | |
| } else { | |
| Write-Warning "No versions found starting with '$BranchPrefix'. Using overall latest version." | |
| $latestVersion = $targetPackage.latestVersion | |
| } | |
| } else { | |
| Write-Warning "Could not parse versions for $PackageName. Using latest version without filtering." | |
| $latestVersion = $targetPackage.latestVersion | |
| } | |
| } | |
| } else { | |
| $latestVersion = $targetPackage.latestVersion | |
| } | |
| if ($null -eq $latestVersion -or $latestVersion -eq "") { | |
| Write-Error "Failed to determine latest version of $PackageName from NuGet." | |
| return $null | |
| } | |
| Write-Host "Latest version of $PackageName is $latestVersion" -ForegroundColor Green | |
| return $latestVersion | |
| } | |
| function Get-RegexPattern { | |
| param( | |
| [string]$PackageName | |
| ) | |
| # Escape special regex characters in package name | |
| $escapedPackage = [regex]::Escape($PackageName) | |
| # Build the full regex pattern for a single package | |
| return '<PackageVersion\s+Include="(' + $escapedPackage + '[^"]*)"\s+Version="([^"]*)"' | |
| } | |
| function Get-MatchingPackages { | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [string]$FilePath, | |
| [Parameter(Mandatory = $true)] | |
| [string[]]$PackagePrefixes | |
| ) | |
| $content = Get-Content -Path $FilePath -Raw | |
| [xml]$xml = $content | |
| $matchingPackages = @() | |
| foreach ($packagePrefix in $PackagePrefixes) { | |
| $matchingPackage = $xml.Project.ItemGroup.PackageVersion | | |
| Where-Object { $_.Include -like "*$packagePrefix*" } | | |
| Select-Object -ExpandProperty Include | |
| $matchingPackages += $matchingPackage | |
| } | |
| return $matchingPackages | |
| } | |
| # Get branch prefix once for all packages | |
| $branchPrefix = Get-BranchPrefix | |
| # Read the file content once | |
| $content = Get-Content -Path $FilePath -Raw | |
| $totalUpdated = 0 | |
| $packageNames = Get-MatchingPackages -FilePath $FilePath -PackagePrefixes $PackagePrefixes | |
| # Process each package name individually | |
| foreach ($packageName in $packageNames) { | |
| Write-Host "`n======================================================" -ForegroundColor Cyan | |
| Write-Host "Processing package: $packageName" -ForegroundColor Cyan | |
| Write-Host "=======================================================" -ForegroundColor Cyan | |
| # Generate regex pattern for this specific package | |
| $pattern = Get-RegexPattern -PackageName $packageName | |
| Write-Host "Generated regex pattern: $pattern" -ForegroundColor Yellow | |
| # Determine version for this specific package | |
| $versionToUse = $null | |
| if ([string]::IsNullOrEmpty($NewVersion)) { | |
| $versionToUse = Get-LatestPackageVersion -PackageName $packageName -BranchPrefix $branchPrefix | |
| if ($null -eq $versionToUse) { | |
| Write-Warning "Skipping $packageName due to version lookup failure" | |
| continue | |
| } | |
| } else { | |
| $versionToUse = $NewVersion | |
| Write-Host "Using provided version: $versionToUse" -ForegroundColor Green | |
| } | |
| # Find matches for this package | |
| $matches = [regex]::Matches($content, $pattern) | |
| $count = $matches.Count | |
| Write-Host "`nFound $count matching package(s) for ${packageName}:" -ForegroundColor Cyan | |
| foreach ($match in $matches) { | |
| $fullPackageName = $match.Groups[1].Value | |
| $currentVersion = $match.Groups[2].Value | |
| Write-Host " - $fullPackageName : $currentVersion" -ForegroundColor Yellow | |
| } | |
| if ($count -eq 0) { | |
| Write-Warning "No packages matching '$packageName' found in $FilePath" | |
| continue | |
| } | |
| # Perform replacement for this specific package | |
| $content = [regex]::Replace($content, $pattern, { | |
| param($match) | |
| $fullPackageName = $match.Groups[1].Value | |
| $oldVersion = $match.Groups[2].Value | |
| Write-Host " Updating $fullPackageName from $oldVersion to $versionToUse" -ForegroundColor Gray | |
| return "<PackageVersion Include=`"$fullPackageName`" Version=`"$versionToUse`"" | |
| }) | |
| $totalUpdated += $count | |
| } | |
| # Write the updated content back to the file | |
| if ($totalUpdated -gt 0) { | |
| Set-Content -Path $FilePath -Value $content -NoNewline | |
| Write-Host "`n========================================" -ForegroundColor Green | |
| Write-Host "Successfully updated $totalUpdated package(s) total" -ForegroundColor Green | |
| Write-Host "========================================" -ForegroundColor Green | |
| } else { | |
| Write-Warning "`nNo packages were updated" | |
| if ($IsDebug) { | |
| Write-Host "`nDebug: First few lines of file:" -ForegroundColor Red | |
| (Get-Content -Path $FilePath | Select-Object -First 50) | ForEach-Object { Write-Host $_ } | |
| } | |
| exit 0 | |
| } | |
| # Verify the updates | |
| Write-Host "`nVerifying updates..." -ForegroundColor Cyan | |
| $verifyContent = Get-Content -Path $FilePath -Raw | |
| foreach ($packageName in $PackagePrefixes) { | |
| $pattern = Get-RegexPattern -PackageName $packageName | |
| $verifyMatches = [regex]::Matches($verifyContent, $pattern) | |
| foreach ($match in $verifyMatches) { | |
| $fullPackageName = $match.Groups[1].Value | |
| $version = $match.Groups[2].Value | |
| Write-Host " ✓ $fullPackageName = $version" -ForegroundColor Green | |
| } | |
| } | |
| if ($IsDebug) { | |
| Write-Host "`nDebug: File contents after update:" -ForegroundColor Red | |
| Write-Host (Get-Content -Path $FilePath -Raw) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment