Downloading NuGet packages with 'System.Net.WebClient' from an Azure DevOps Artifact feed

Background

We use Lability to build Windows Server images for our test labs. Lability makes use of Desired State Configuration (DSC) to build the VM images. Part of this process is for Lability to download DSC modules, as ZIP files, from a NuGet feed such as PowerShell Gallery to inject into the created VM image.

Historically, we have stored our own private DSC modules on an internally hosted NuGet server. However, we wanted to move these modules to a private Azure DevOps Artifacts feed. The problem was that Lability does not support downloading of DSC modules from Azure DevOps Artifact feeds, whether they are public or private, because of the way the package URLs are constructed.

I am in the process of creating a PR for Lability to add support for Azure DevOps Artifact feeds, but I thought it worth this quick blog post on package URL formats as it might be useful to others.

The URL format for downloading a package from the PowerShell Gallery is well known, being

1https://www.powershellgallery.com/packages/<package name>/<version>

Enter this URL in a browser and the requested package will be downloaded

URLs for Azure DevOps Artifacts

You might well expect the format for downloading a package from Azure DevOps Artifacts to be

1https://pkgs.dev.azure.com/<AzDo Org>/_packaging/<Feed Name>/nuget/v2/Packages/<package name>/<version>

but it is not.

Stackoverflow suggests the URL format is

1https://pkgs.dev.azure.com/<AzDo Org>/_packaging/<Feed Name>/nuget/v2/Packages(id=<Package name>,version=<version>)

However, this does not download a package, but rather an XML manifest file. But from this manifest we can see a <content> element that contains the URL to the package, and it is an interesting format.

So for the manifest URL

1https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v2/Packages(id=xNetworking,version=5.7.0.0)

the content URL is

1https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v2?id=xnetworking&version=5.7.0

Note that

  • the package name is lower case
  • the four part version number is replaced with a three part version number
  • the XML encoded &amp; value in the manifest is replaced with a simple &

The following gist is a function to build the required URL from the package name and version number and download the package as a ZIP file

Hope this helps someone and saves them some time.