Skip to content

Instantly share code, notes, and snippets.

@BuriedStPatrick
Last active November 13, 2023 17:18
Show Gist options
  • Save BuriedStPatrick/469b92bbff1b328218ee78a27536f082 to your computer and use it in GitHub Desktop.
Save BuriedStPatrick/469b92bbff1b328218ee78a27536f082 to your computer and use it in GitHub Desktop.
Manage PackageReferences with PowerShell

Manage PackageReferences with PowerShell

These are a couple of useful scripts -- for use in tandem -- that make it easier to migrate PackageReference Include=... items to a common Packages.props file. Use them in combination with each other like:

New-PackagesProps (Get-PackageReference ./MySolution.sln) | Set-Content -Path ./Packages.props

Or, you can use the Get-SolutionProject to get the projects referenced in the solution:

Get-SolutionProject ./MySolution.sln

Or, if you have intentions of just getting packages from solution(s) or project(s):

# Will traverse referenced projects and spit out their PackageReferences
Get-PackageReference ./MySolution.sln

# Will output all PackageReferences in project
Get-PackageReference ./MyProject.csproj

# Will output all PackageReferences in input projects
Get-ChildItem -Recurse *.csproj | Get-PackageReference
# Get all PackageReferences from a project or solution
# Does NOT include transient dependencies
# Example A: Get-PackageReference ./MySolution.sln
# Example B: Get-ChildItem -Recursive *.csproj | Get-PackageReference
function Get-PackageReference {
[CmdletBinding()]
param (
[Parameter(
Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
[AllowNull()]
[AllowEmptyString()]
[string] $Path
)
process {
return $Path | ForEach-Object {
if (!(Test-Path $_)) {
throw "Cannot locate '$_'"
}
if ($_.EndsWith(".sln")) {
$solutionProjects = Get-SolutionProject -Path $_
return $solutionProjects | Get-PackageReference
}
$xml = [xml](Get-Content $_ | Out-String)
return $xml.SelectNodes('//PackageReference') | ForEach-Object {
[PSCustomObject]@{
'Id' = $_.GetAttribute('Include')
'Version' = $_.GetAttribute('Version')
}
}
}
}
}
# Get referenced .NET csproj projects from .sln file
# Is kind of dumb, just looks for a line starting with Project and containing the '.csproj' keyword
# Example A: Get-SolutionProject ./MySolution.sln
# Example B: Get-ChildItem -Recurse *.sln | Get-SolutionProject
function Get-SolutionProject {
[CmdletBinding()]
param (
[Parameter(
Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "Path to the solution .sln file"
)]
[AllowNull()]
[AllowEmptyString()]
[string] $Path
)
process {
return $Path | ForEach-Object {
$solutionPath = $_
if (!(Test-Path $solutionPath)) {
throw "Cannot locate solution at '$solutionPath'"
}
return Get-Content -Path $solutionPath | ForEach-Object {
if (!($_.StartsWith("Project(`"{"))) {
return
}
if (!($_.Contains('.csproj'))) {
return
}
$path = (Join-Path (Get-item $solutionPath).Directory.FullName ($_.Split(',')[1].Trim().Replace('"', '')))
$pathExists = Test-Path $path
return [PSCustomObject]@{
Name = ($_.Split('=') | Select-Object -Last 1).Split(',')[0].Trim().Replace('"', '')
Path = $pathExists ? (Convert-Path $path) : $path
Exists = $pathExists
}
}
}
}
}
# Outputs a Packages.props-like file based on Package Reference objects. Useful for converting existing .csproj PackageReferences into a centralized Packages.props file with "Update" instead of "Include"
# Splits package references into Microsoft & other packages for convenience
# Example A: New-PackagesProps (Get-PackageReference ./MySolution.sln) | Set-Content -Path ./Packages.props
function New-PackagesProps {
[CmdletBinding()]
param (
[Parameter(
Mandatory = $true,
HelpMessage = "Converts .csproj PackageReferences to Packages.props"
)]
[AllowNull()]
[AllowEmptyString()]
[PSCustomObject[]]
$PackageReference
)
process {
$msPackages = @()
$otherPackages = @()
$PackageReference | ForEach-Object {
$package = $_
if ($package.Id.StartsWith('Microsoft')) {
$msPackages += $package
return
}
$otherPackages += $package
}
$msPackages = $msPackages | ForEach-Object {
return "$([System.Environment]::NewLine) <PackageReference Include=`"$($_.Id)`" Version=`"$($_.Version)`" />"
}
$otherPackages = $otherPackages | ForEach-Object {
return "$([System.Environment]::NewLine) <PackageReference Include=`"$($_.Id)`" Version=`"$($_.Version)`" />"
}
$result =
@"
<Project>
<!-- Microsoft Packages -->
<ItemGroup>$($msPackages)
</ItemGroup>
<!-- Other packages -->
<ItemGroup>$($otherPackages)
</ItemGroup>
</Project>
"@
return $result
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment