Download all your NuGet Package Licenses

oss nuget 15 comments suggest edit

The other day I was discussing the open source dependencies we had in a project with a lawyer. Forgetting my IANAL (I am not a lawyer) status, I made some bold statement regarding our legal obligations, or lack thereof, with respect to the licenses.

I can just see her rolling her eyes and thinking to herself, “ORLY?” She patiently and kindly asked if I could produce a list of all the licenses in the project.

Groan! This means I need to look at every package in the solution and then either open the package and look for the license URL in the metadata, or I need to search for each package and find the license on NuGet.org.

If only the original creators of NuGet exposed the package metadata in a structured manner. If only they had the foresight to provide that information in a scriptable fashion.

Then it dawned on me. Hey! I’m one of those people! And that’s exactly what we did! I bet I could programmatically access this information. So I immediately opened up the Package Manager Console in Visual Studio and cranked out a PowerShell script…HA HA HA! Just kidding. I, being the lazy ass I am, turned to Google and hoped someone else figured it out before me.

I didn’t find an exact solution, but I found a really good start. This StackOverflow answer by Matt Ward shows how to download every license for a single package. I then found this post by Ed Courtenay to list every package in a solution. I combined the two together and tweaked them a bit (such as filtering out null project names) and ended up with this one liner you can paste into your Package Manager Console. Note that you’ll want to change the path to something that makes sense on your machine.

I posted this as a gist as well.

@( Get-Project -All | ? { $_.ProjectName } | % { Get-Package -ProjectName $_.ProjectName } ) | Sort -Unique | % { $pkg = $_ ; Try { (New-Object System.Net.WebClient).DownloadFile($pkg.LicenseUrl, 'c:\dev\licenses\' + $pkg.Id + ".txt") } Catch [system.exception] { Write-Host "Could not download license for $pkg" } }

UPDATE: My first attempt had a bug in the catch clause that would prevent it from showing the package when an exception occurred. Thanks to Graham Clark for noticing it, Stephen Yeadon for suggesting a fix, and Gabriel for providing a PR for the fix.

Be sure to double check that the list is correct by comparing it to the list of package folders in your packages directory. This isn’t the complete list for my project because we also reference submodules, but it’s a really great start!

I have high hopes that some PowerShell guru will come along and improve it even more. But it works on my machine!

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

15 responses

  1. Avatar for Sachin Joseph
    Sachin Joseph March 29th, 2015

    Wow! That's cool! :-)

  2. Avatar for Robin Osborne
    Robin Osborne March 30th, 2015

    Ok, that's handy - time to hook it into a build step..

  3. Avatar for Graham Clark
    Graham Clark March 30th, 2015

    In the "Catch" block, the $_ variable will refer to the exception, not the current package. I'm no powershell expert, but you could assign $_ to another variable before the Try.... like

    ForEach-Object { $p = $_; Try { (New-Object System.Net.WebClient).DownloadFile($p.LicenseUrl, 'c:\dev\licenses\' + $p.Id + ".txt") } Catch [system.exception] { Write-Host "Could not download license for $p.Id, $_" } }
  4. Avatar for Stephen Yeadon
    Stephen Yeadon March 30th, 2015

    That is a sweat one liner, but Graham is correct the variable $_ holds the error value when in the catch block not the package. The below code fixes that.


    @( Get-Project -All |
    ? { $_.ProjectName } |
    % { Get-Package -ProjectName $_.ProjectName } ) |
    Sort -Unique |
    % { $pkg = $_ ; Try { (New-Object System.Net.WebClient).DownloadFile($pkg.LicenseUrl, 'c:\dev\licenses\' + $pkg.Id + ".txt") } Catch [system.exception] { Write-Host "Could not download license for $pkg.Id" } }
  5. Avatar for Gabriel
    Gabriel March 30th, 2015

    Have created a pulled request for this

  6. Avatar for haacked
    haacked March 30th, 2015

    Thanks for the fix! And thanks to Garbriel for submitting a pull request!

  7. Avatar for Paulo Morgado
    Paulo Morgado March 30th, 2015

    It would be easier if the package owner was required to add the license to the project.

  8. Avatar for Greg Sohl
    Greg Sohl March 31st, 2015

    You mean you didn't already know how the OS software you were using was licensed?? Ouch. I suggest that anyone who pulls an outside piece of software in vet it carefully, document what they are using, how it is licensed and make sure the license has been approved by your legal team, if available.

  9. Avatar for haacked
    haacked March 31st, 2015

    Well *I* knew, but my lawyer didn't.

  10. Avatar for Tim Bendt
    Tim Bendt March 31st, 2015

    gist pls?

  11. Avatar for haacked
    haacked March 31st, 2015

    You asked for it! You geti it! https://gist.github.com/Haa...

  12. Avatar for Tom Robinson
    Tom Robinson April 7th, 2015

    I've created a fork which puts the license files into a "licenses" directory in the solution root, and uses the .html suffix, as most (all?) of the ones I've looked at so far have been HTML formatted.

    https://gist.github.com/tjr...

  13. Avatar for brlinton
    brlinton September 18th, 2015

    Looks like this doesn't work anymore in VS2015 / latest NuGet? http://stackoverflow.com/qu...

  14. Avatar for ekblom
    ekblom February 22nd, 2016

    Its not working for me either. An issue has been posted to nuget repo https://github.com/NuGet/Ho...

  15. Avatar for Peter Reskovic
    Peter Reskovic June 3rd, 2016

    Thanks for this, really helpful. Based on this and the suggestions from the comments plus some fixes to make it work in our current environment (VS2015 Update 2) I've ended up with the modified version posted here http://stackoverflow.com/a/...