Skip to content

Instantly share code, notes, and snippets.

@a4099181
Last active February 18, 2021 07:00
Show Gist options
  • Save a4099181/074a6c3dd524ea0d343382137492399c to your computer and use it in GitHub Desktop.
Save a4099181/074a6c3dd524ea0d343382137492399c to your computer and use it in GitHub Desktop.
Converts packages.config into PackageReference at *.csproj project file. Requires XSLT stylesheet available as second file in the gist.
Function Convert-ToPackageReference
{
Param ( [Parameter( Mandatory, ValueFromPipeline )][String] $inputUri,
[String] $stylesheetUri = "https://gist.githubusercontent.com/a4099181/074a6c3dd524ea0d343382137492399c/raw/cdd0fb31efd70c4c0f8c86ddb314de86ab8972e8/Convert-ToPackageReference.xsl",
[String] $resultsFile = [System.IO.Path]::GetTempFileName() )
Process {
$xslt = New-Object System.Xml.Xsl.XslCompiledTransform
$xslt.Load( $stylesheetUri )
$xslt.Transform( $inputUri, $resultsFile )
Get-Content $resultsFile
}
}
Function Update-ProjectFile
{
Param ( [Parameter( Mandatory )][String] $projectFile,
[Parameter( Mandatory, ValueFromPipeline )][String] $content )
Begin { $packageReference = '' }
Process { $packageReference += $content }
End {
$projXml = New-Object System.Xml.XmlDocument
$projXml.Load( $projectFile )
$nameSpc = New-Object System.Xml.XmlNamespaceManager $projXml.NameTable
$nameSpc.AddNamespace("x", "http://schemas.microsoft.com/developer/msbuild/2003");
$prefXml = New-Object System.Xml.XmlDocument
$prefXml.LoadXml( $packageReference )
$prefXml.SelectNodes( "/x:Project/x:ItemGroup/x:PackageReference", $nameSpc ) |
% {
$pkgNode = $projXml.ImportNode( $_, $true )
$pkgName = $_.Include.Split('-')[0]
$version = $_.Version
$nodes = $projXml.SelectNodes( "/x:Project/x:ItemGroup/x:Reference", $nameSpc ) |
? Include -Like "$pkgName*"
if ( $nodes.Count -eq 0 )
{
Write-Information "$projectFile $pkgName package outside the project file."
$itemGroup = $projXml.CreateElement( "ItemGroup", $nameSpc.LookupNamespace( "x" ) )
$itemGroup.AppendChild( $pkgNode )
$projXml.DocumentElement.AppendChild( $itemGroup )
}
else {
$nodes | % {
if ( $_.Include -Match "$version" )
{
Write-Information "$projectFile $pkgName valid reference."
$_.ParentNode.AppendChild( $pkgNode )
$_.ParentNode.RemoveChild( $_ )
}
else
{
Write-Warning "$projectFile $pkgName version mismatched."
$_.ParentNode.InsertBefore( $pkgNode, $_ )
}
}
}
}
$projXml.SelectNodes( "/x:Project/x:ItemGroup/x:*[@Include='packages.config']", $nameSpc ) |
% { $_.ParentNode.RemoveChild( $_ ) }
$projXml.Save( $projectFile )
}
}
Get-ChildItem . -Recurse -File -Filter packages.config |
select @{ Name="ProjectFile"; Expression={ "$($_.Directory)\$($_.Directory.BaseName).csproj" } },
@{ Name="PackagesConfig"; Expression={ $_.FullName } } |
? { Test-Path $_.ProjectFile } |
% {
$_.PackagesConfig | Convert-ToPackageReference | Update-ProjectFile $_.ProjectFile -InformationAction Continue
Remove-Item $_.PackagesConfig
}
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<xsl:output omit-xml-declaration="yes" method="xml" indent="no"/>
<xsl:template match="/">
<xsl:element name="Project">
<xsl:element name="ItemGroup">
<xsl:apply-templates/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="package">
<xsl:element name="PackageReference">
<xsl:attribute name="Include">
<xsl:value-of select="@id" />
</xsl:attribute>
<xsl:attribute name="Version">
<xsl:value-of select="@version" />
</xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
@a4099181
Copy link
Author

a4099181 commented Mar 24, 2017

Use it only for solutions secured with any control version system (maybe git). If you are satisfied with results then commit.

Usage tip

Open Powershell prompt and type:

PS > cd solution\folder
PS solution\folder> iwr https://git.io/vxjY1 -OutFile Convert-ToPackageReference.ps1
PS solution\folder> ./Convert-ToPackageReference.ps1 | Out-Null

Synopsis

This script recognizes three possibilities:

  1. nuget package is declared in packages.config but missing in the project file.
    PackageReference is appended to the project file.
  2. nuget package declared in packages.config and corresponding reference is placed into the project file, but:
    • versions in the project file and packages.config are equal.
      Reference is replaced with PackageReference
    • version in the project file is not equal to version in the packages.config file.
      PackageReference is inserted before Reference. Warning is written to the output.
      User attention is requested. Please, clean up references manually with Visual Studio.
      If you don't want to care about the version, you can simply tweak/edit the script to ignore it.

Enjoy new nuget package references with MSBuild 15 or Visual Studio 2017 ;)

@aienabled
Copy link

aienabled commented Oct 11, 2017

@a4099181, thank you for this script, but unfortunately it doesn't work for me.
I can see that your "usage tip" doesn't include downloading xslt file too. I've downloaded it manually but it still doesn't work - I execute ./Convert-ToPackageReference.ps1 and get no any response (so it silently executes), no changes are done (as I can see with git).

UPD. It seems it cannot locate project files in my case, as their names don't match the folder names.

UPD. Ok, I was able to rewrite bottom part of this script to make it usable for case when .csproj file name doesn't match the folder name:

Get-ChildItem . -Recurse -File -Filter packages.config |
    select @{ Name="ProjectFile";    Expression={ (Get-ChildItem -Path "$($_.Directory)\*.csproj").FullName } },
           @{ Name="PackagesConfig"; Expression={ $_.FullName } } |
    ? { $_.ProjectFile } |
    % {
        Write-Host "Found: " $_.ProjectFile
        $_.PackagesConfig | Convert-ToPackageReference | Update-ProjectFile $_.ProjectFile -InformationAction Continue
        Remove-Item $_.PackagesConfig
    }

My fork https://gist.github.com/aienabled/0bce5e4b17118122f2772e7c9218bf9c

@a4099181
Copy link
Author

@aienabled Fine, well done. I'm very glad that you've got it worked out and my script is useful anyway. Yes, "usage tip" does not include downloading xslt file. It is not required while

$xslt.Load( $stylesheetUri )

is able to handle xslt file from web.

@agat366
Copy link

agat366 commented Jan 26, 2018

The script saved my night! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment