Skip to content

Instantly share code, notes, and snippets.

@Wind010
Last active January 9, 2026 20:09
Show Gist options
  • Select an option

  • Save Wind010/db6e883efa7a6c2d824514efeebd3b85 to your computer and use it in GitHub Desktop.

Select an option

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.
# 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