17

How can I check if nuget package with specific version exists in a specified package source (nuget server) using powershell or commandline outside visual studio?

Scenario:

I have private NuGet server where I want to push my own packages. I have automated creation of the packages during TFS build. What I miss is check, if the package was previously uploaded and published to the NuGet Server.

6
  • nuget.exe list -source <urlforyoursourcehere> (see nuget.exe list -help for the possible filters and so on). Commented Feb 25, 2016 at 16:43
  • 1
    I'm affraid that this is too much overhead, since I would need to download all version of all packages: nuget list -source <mynugetserver> -Prerelease -AllVersions Commented Feb 25, 2016 at 16:53
  • Ahh, didn't see this comment before posting new answer. Going to delete both answers. Commented Feb 25, 2016 at 16:59
  • 3
    You can filter the list by providing the package name you are searching for: nuget.exe <yourpackagename> list -source <yoursource> Commented Feb 25, 2016 at 17:02
  • 1
    @Liero the list command returns also packages which contain in the name or in the tags the provided keyword after list. Can you share what is your current solution? May be you can post it as an answer... 10x Commented Jul 27, 2016 at 20:57

5 Answers 5

7

I do not know if your private NuGet server implements the same server Api as nuget.org, but I will assume it does. https://learn.microsoft.com/en-us/nuget/api/registration-base-url-resource describes the API that can be used to check if a package is published and get its versions. Unlike nuget list command it performs exact match by the package Id.

For example, suppose you wish to know whether the package AjaxMin is published. Executing nuget list ajaxmin is not very helpful:

C:\> nuget.exe list ajaxmin
BundleTransformer.MicrosoftAjax 1.10.0
Bundler.NET 1.5.7
CodeSlice.Web.Baler.Extensions.AjaxMinifier 0.2.0
combres 2.3.0.4
combres.log4net 2.3.0.4
combres.mvc 2.3.0.4
Delegate.AjaxMinBuilder 1.1.2
DotLessMinification 0.42.1
AjaxMin 5.14.5506.26202
NUglify 1.5.1
NUglify 1.5.13
Pvc.Ajaxmin 0.0.2
RequestReduce 1.8.76
WebMarkupMin.Core 2.6.0
WebMarkupMin.MsAjax 2.6.0
Web.Optimization.Bundles.AjaxMin 0.0.8
Web.Optimization.Bundles.YUI 0.0.8
C:\>

Yes, you can filter the output, but I find it too much work. You can be more precise by using the server Api. Observe:

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/index.json'
C:\> $res = Invoke-RestMethod $url
C:\> $res.items.items.catalogEntry.version
4.12.4057.21792
4.13.4076.28499
4.19.4141.18463
4.30.4295.16112
4.36.4337.24224
4.37.4345.34101
4.39.4362.37207
4.40.4369.35534
4.41.4378.21434
4.42.4387.23950
4.43.4392.20083
4.44.4396.18853
4.45.4416.14249
4.46.4422.26284
4.47.4452.34008
4.48.4489.28432
4.49.4503.16524
4.50.4504.34801
4.51.4507.18296
4.52.4518.14738
4.53.4526.21623
4.54.4533.37029
4.55.4545.19776
4.56.4560.33404
4.58.4566.27257
4.59.4576.13504
4.60.4609.17023
4.61.4617.31171
4.62.4618.15628
4.63.4630.14654
4.64.4630.17932
4.66.4633.35991
4.67.4639.17289
4.68.4663.23906
4.69.4665.24361
4.70.4668.12892
4.71.4679.26350
4.72.4679.35523
4.73.4685.17669
4.74.4698.25434
4.75.4713.17606
4.76.4714.20550
4.77.4723.25304
4.78.4724.23869
4.80.4763.16598
4.81.4769.14860
4.82.4784.14537
4.83.4785.14876
4.84.4790.14417
4.85.4828.21154
4.86.4836.34222
4.89.4861.30057
4.90.4864.13402
4.91.4875.26882
4.92.4896.13361
4.93.4902.12739
4.94.4916.15482
4.95.4924.12392
4.96.4941.15389
4.97.4951.28483
5.0.5007.14585
5.1.5007.23730
5.2.5021.15814
5.3.5068.16463
5.4.5085.25629
5.5.5091.22839
5.6.5100.19204
5.7.5124.21499
5.8.5172.27710
5.9.5229.26438
5.10.5260.16959
5.11.5295.12309
5.12.5436.22734
5.13.5463.15282
5.14.5506.26202
C:\>

We get all the versions of the package. Now, if you want to check if a certain version known beforehand is published - you can:

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/5.14.5506.26202.json'
C:\> $res = Invoke-RestMethod $url
C:\> $res


@id            : https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/5.14.5506.26202.json
@type          : {Package, http://schema.nuget.org/catalog#Permalink}
catalogEntry   : https://api.nuget.org/v3/catalog0/data/2018.10.06.23.54.33/ajaxmin.5.14.5506.26202.json
listed         : True
packageContent : https://api.nuget.org/v3-flatcontainer/ajaxmin/5.14.5506.26202/ajaxmin.5.14.5506.26202.nupkg
published      : 2015-01-28T22:45:45.577+00:00
registration   : https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/index.json
@context       : @{@vocab=http://schema.nuget.org/schema#; xsd=http://www.w3.org/2001/XMLSchema#; catalogEntry=; registration=; packageContent=; published=}



C:\>

Now what happens if we ask for a version that does not exist? Here we go:

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/5.14.5506.26196.json'
C:\> $res = Invoke-RestMethod $url
Invoke-RestMethod : BlobNotFoundThe specified blob does not exist.
RequestId:cd1579e6-801e-007d-5eba-64ac9d000000
Time:2019-09-06T13:53:54.6832811Z
At line:1 char:8
+ $res = Invoke-RestMethod $url
+        ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
C:\>

How about asking for a non existing package? Let us search for ajaxmi (no 'n'):

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmi/index.json'
C:\> $res = Invoke-RestMethod $url
Invoke-RestMethod : BlobNotFoundThe specified blob does not exist.
RequestId:23d96274-b01e-0018-3bba-641dc0000000
Time:2019-09-06T13:55:35.5288968Z
At line:1 char:8
+ $res = Invoke-RestMethod $url
+        ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
C:\>
Sign up to request clarification or add additional context in comments.

Comments

5

You can call this CMD script from PowerShell easy enough, with examples below it. You can just go by $LastExitCode to determine how to proceed, with 0 meaning you can publish:

check_nupkg.bat

@echo off
SetLocal EnableDelayedExpansion EnableExtensions
pushd "%~dp0"

set "pkg_name=%~1"
set "pkg_version=%~2"

call nuget list %pkg_name% -AllVersions -Prerelease|findstr /i /r /c:"^%pkg_name% %pkg_version%$" -N>nul 2>&1

if not "%errorlevel%"=="0" (
    echo This package can be published
    exit /b 0
) else (
    echo This package has already been published.
    exit /b 1
)

C:\stuff>.\check_nupkg.bat "lolspeak" "1.0.0"

This package has already been published.

C:\stuff>check_nupkg.bat "lolspeak" "11.0.0"

This package can be published

Comments

2

The approach that I had used, which was based on some of the other answers, recently break, so I want to describe more fully how we go about discovering the URLs and doing the actual validation.

NuGet.org provides a service index that provides the list of base URLs as indexed by type. This service index is available at https://api.nuget.org/v3/index.json.

It returns data in the following structure (truncated for brevity):

PS> Invoke-RESTmethod -uri 'https://api.nuget.org/v3/index.json'

version resources
------- ---------
3.0.0   {@{@id=https://azuresearch-usnc.nuget.org/query; ... 

In other words, the service index provides a set of available API versions and a corresponding set of resources (i.e., endpoints/queryable APIs). Those resources correspond to URLs that have very specific capabilities and which should all be documented. at the time of this writing, we only have version 3.0.0 as an option, so let's examine those resources we can see what those endpoints look like, filtering the output to endpoints related to package registration and metadata:

PS> (Invoke-RESTmethod -uri 'https://api.nuget.org/v3/index.json' | `
    ? { $_.version -eq '3.0.0' }).resources | `
    ? { $_.'@type' -like '*Registration*' } | `
    select-object -Property '@id','@type'

@id                                                @type
---                                                -----
https://api.nuget.org/v3/registration4/            RegistrationsBaseUrl
https://api.nuget.org/v3/registration4/            RegistrationsBaseUrl/3.0.0-rc
https://api.nuget.org/v3/registration4/            RegistrationsBaseUrl/3.0.0-beta
https://api.nuget.org/v3/registration4-gz/         RegistrationsBaseUrl/3.4.0
https://api.nuget.org/v3/registration4-gz-semver2/ RegistrationsBaseUrl/3.6.0
https://api.nuget.org/v3/registration4-gz-semver2/ RegistrationsBaseUrl/Versioned

One useful property that I left off the output is that a comment property exists that provides a useful description of the endpoint. For example, for RegistrationsBaseUrl we have the following comment:

Base URL of Azure storage where NuGet package registration info is stored

From the above, we can see that our base URL will be one of the URLs above on the left. Checking the docs for @type RegistrationsBaseUrl:

These registrations are not compressed (meaning they use an implied Content-Encoding: identity). SemVer 2.0.0 packages are excluded from this hive.

For my needs, I want to include SemVer 2.0.0, so I want to use a different endpoint. Again checking the docs:

These registrations are compressed using Content-Encoding: gzip. SemVer 2.0.0 packages are included in this hive.

So, per the earlier query results I want the following url:

https://api.nuget.org/v3/registration4-gz-semver2/

In reading through the documentation we learn that we're interested in the Registration Page for the package that we're trying to query. The URL syntax will be:

$BASEURL/<PackageName>/<PackageVersion>.json

Using Newtonsoft.Json as a sample package and expanding:

https://api.nuget.org/v3/registration4-gz-semver2/newtonsoft.json/12.0.3.json

Now that we know how we get the URL, and the fact that it can change over time and should be dynamically retrieved, let's write some PowerShell that will determine whether a NuGet package has been published to a given source:

param (
  [Parameter(Mandatory=$true)] 
  [string]$Id,
  [Parameter(Mandatory=$true)] 
  [string]$Version,
  [Parameter(Mandatory=$false)] 
  [string]$source = "https://api.nuget.org/v3/index.json"
)

$resources = (invoke-restmethod -uri $source | ? { $_.version -eq '3.0.0' }).resources
$baseUrl = ($resources | ? { $_.'@type' -eq 'RegistrationsBaseUrl/3.6.0' }).'@id'

try
{
  $packageName = $Id.ToLowerInvariant()
  $packageVersion = $Version.ToLower()

  # Use supported HEAD method for performance
  Invoke-RestMethod -uri "$($baseUrl)$($packageName)/$($packageVersion).json" -Method HEAD > $null 2>&1
  # method didn't throw so the NuGet package exists
  $true
}
catch
{
  # method threw, so the NuGet package doesn't exist
  $false
}

Its use would look like the following:

PS>  Get-NuGetPackageExists.ps1 -Id Newtonsoft.Json -Version 10.0.2
True

Comments

0

Also you can check exist or not the package on the server with a browser (or any tool which can send HTTP-GET request) just by getting package description. For example we recieve description for the package System.Collections.Immutable and we get 404 status code for non existing package. These urls are case sensitivity.

Comments

-4

If you use PowerShell 5.0 it has PackageManagement cmdlets built-in. You can use these to discover and install the various packages. Here is a reference https://technet.microsoft.com/en-us/library/dn890706.aspx

1 Comment

This answer does not provide any help. -1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.