Visual Studio extensions are great to extend and add additional features/enhancements to the Visual Studio IDE. Unfortunately, until now there was no better way to implement a proper CI/CD for your Visual Studio extensions. In this blog post I will show you how you can setup continuous build and deployment for your Visual Studio extensions.

If you have been an Visual Studio extension developer you know that there is not a well defined process to continuously deliver to the Visual Studio Marketplace. Couple of years ago, Mads Kristensen’s Extensibility Tools in combination with his reduced some pain where you could implement CI/CD to his vsixgallery, but eventually you still had to manually upload the extension to VS Marketplace upon your testing.

Fortunately there is a now a new command line tool called VSIXPublisher from Microsoft. With this tool we can continuously build and deploy our Visual Studio extensions using Azure Pipelines to VS Marketplace.

The command line

The VSIXPublisher exe is installed with Visual Studio SDK and also available via VSSDK Build Tools nuget. The command line provides us various commands to

  • Login and Logout
  • Publish the extension
  • Create the publisher
  • Delete the publisher
  • Delete the extension

In this post we will only be using login and publish commands. But you can see that tool also supports other useful features like create/delete publisher or delete your extension from marketplace.

For publishing an Visual Studio extension using this tool you will need a publisher id and a personal access token (PAT). For this post, I am assuming you already have a publisher id. If not go ahead and use the command line to create the publisher for yourself. For creating PAT, you will need to follow steps defined here

Preparing your extension for publishing

  • For this post, I will be using a demo extension called InfoBar Demo which referenced in my earlier blog post.
  • The source of the extension is open source on GitHub here

The first thing we need is to add a publishManifest file. This is a simple JSON file describing metadata of your extension. For more details on the structure read here

You can name your manifest file anything you like. For my extension I created a manifest file as extension.manifest.json (link) with contents as below.

  "$schema": "",
  "categories": [ "build", "coding" ],
  "identity": {
    "internalName": "InfoBarDemo"
  "assetFiles": [
      "pathOnDisk": "images\\custom-command-item.png",
      "targetPath": "images/custom-command-item.png"
      "pathOnDisk": "images\\extension-dev-workload.png",
      "targetPath": "images/extension-dev-workload.png"
      "pathOnDisk": "images\\image-catalog-reference.png",
      "targetPath": "images/image-catalog-reference.png"
      "pathOnDisk": "images\\new-project.png",
      "targetPath": "images/new-project.png"
      "pathOnDisk": "images\\tools-menu-item.png",
      "targetPath": "images/tools-menu-item.png"
      "pathOnDisk": "images\\vs-infobar-actions.png",
      "targetPath": "images/vs-infobar-actions.png"
      "pathOnDisk": "images\\vs-infobar.png",
      "targetPath": "images/vs-infobar.png"
  "overview": "",
  "priceCategory": "free",
  "publisher": "onlyutkarsh",
  "private": false,
  "qna": true,
  "repo": ""

Notice that I have my extension overview page as “” (The contents of appear on extension home page in the VS Marketplace). And because I have few images referenced in my file, I need to add and correctly map all the referenced images under assetFiles section.

Next, verify and adjust other information like Product ID, Description etc in your source.extension.vsixmanifest file. For example, I added the Description and also added preview image which appear in the marketplace page. You can check the commit here.

Setting up the Build in Azure Pipelines (Continuous Build)

My extension targets Visual Studio 2017 and building the extension is simple on Azure DevOps Service’s Hosted Agents as it already has Visual Studio 2017 installed.

So I created a new build pipeline and added the GitHub repo as source.

Add Source

The next action we need to take is, adding the build steps to generate build artifacts to publish to marketpace. We will be publishing number of files as build artifacts - E.g., VSIX file, publishManifest file etc.

Build Steps

As you can see from the image above, I am doing following operations in my build definition,

  • Get all the nuget references using Nuget restore
  • Build the solution
  • Copy the vsix file to artifacts directory
  • Copy the files required for marketplace ( and publishManifest files) to artifacts directory
  • Copy all the images referenced in in the same structure to artifacts directory
  • Finally publish the artifacts directory as build artifact so that it can be consumed for deployment.

For simplicity, I am not incrementing the version of the extension here, but you may also want to increment version each time you trigger the build.

The final artifacts produced by the build are like this.

Build Artifacts

Setting up the Release in Azure Pipelines (Continuous Deployment)

Now that our build produces the artifact we need correctly, its time to set the release pipeline and publish our extension to VS Marketplace.

Head over to Releases hub and create New release pipeline. I have added a single stage called marketplace as below. I have added build output we created in previous step as an artifact.

Add Artifact

  1. I am running this release pipeline on Hosted VS2017 pool as I know it has Visual Studio 2017 and also has VSSDK installed. How do I know that? A new Azure DevOps agents show all the software’s installed within the pipeline itself. Pool Information
  2. VSIXPublisher.exe is available from VSSDK folder under Visual Studio install directory at ${VSInstallDir}\VSSDK\VisualStudioIntegration\Tools\Bin\VsixPublisher.exe and Hosted VS2017 pool shows me that component Microsoft.VisualStudio.Component.VSSDK is available - which is Component ID for Visual Studio SDK. Pool Details

Okay, we now have everything we need, right artifacts and right agent pool to do our deployments. So lets add steps to deploy our extension. My deployment has following steps.

Deploy Steps

As you can see from the screen shot above, this is what I am doing in my deployment.

  1. Identify the VSIXPublisher install location and make it available as a pipeline variable so that it can be consumed by other tasks in the pipeline. I am doing this using a out of the box Powershell task.

Detect Vsix Publisher

The Powershell used in the task is as below

$VisualStudioVersion = "15.0";
$VSINSTALLDIR =  $(Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7").$VisualStudioVersion;
$VSIXPublisherPath= $VSINSTALLDIR + "VSSDK\VisualStudioIntegration\Tools\Bin\VsixPublisher.exe"

Write-Host "##vso[task.setvariable variable=VSINSTALLDIR ]$VSINSTALLDIR"
Write-Host "##vso[task.setvariable variable=VSIXPublisherPath]$VSIXPublisherPath"

In the first 3 lines, I am detecting the installed location of the Visual Studio 2017 using the registry key. 15.0 is the internal version of Visual Studio 2017.

In the last two lines of the code, I am dynamically generating two pipeline variable using logging commands. The critical line to note is, in the last line of the script I am setting the complete VSIXPublisher.exe path to a variable named VSIXPublisherPath.

  1. In the second step of the pipeline, I am just verifying that the variable set in the above step is available to us, by printing all the variables in the pipeline. And based on the deployment logs I see that it is available. Variables

  2. To publish the extension to the marketplace, we first need to login using VSIXPublisher too. The next step is doing exactly that. For this command we need to pass our PAT token used for our publisher account. The login command syntax is as below.

VsixPublisher.exe login -personalAccessToken "{Personal Access Token}" -publisherName "{Publisher Name}"

So I add my PAT token and my publisher name and add them as Pipeline variables so that they are available for pipeline tasks. I made sure I mark my PAT token as a secure variable so that it does not show up in the deployment logs.

Additional Variables

If everything went right, during deployment you will see the login successful message.

Login Log

  1. The final step is to actually publish the extension. The command for publishing the VSIX is as below.
VsixPublisher.exe publish -payload "{path to vsix}" -publishManifest "{path to vs-publish.json}" -ignoreWarnings "VSIXValidatorWarning01,VSIXValidatorWarning02"

Publish Extension Ui

When I ran this command initially the deployment did show a warning of type VSIXValidatorWarning03 as shown in screenshot below. The warning was that my extension does not derive from AsyncPackage. This is a valid warning, as starting with Visual Studio 2019, synchronous auto loading of extension will not be supported.

Vsix Publisher Warning

However, for this demo extension, I decided to ignore the warning. So I updated the command to ignore the warning.

Vsix Publisher Ignore Warning

The Release Pipeline deployment logs shows exactly the same output.

Vsix Publisher Ui Logs

That’s it, at this point marketplace will validate your extension and makes your extension available.


See my Demo extension on the VS marketplace here

Future plans and Conclusion

I am working on transforming this in to an open source marketplace extension so that its easy to consume. It will hopefully also make others to use it as is without passing parameters/creating variables. I will post an update once the extension is avaiable.

If you are an extension developer as I am, doing CI/CD for your Visual Studio extensions is pretty exciting stuff. You could not do continuous delivery of your Visual Studio extensions previously. Having made VSIXPublisher.exe tool available, developers can now deliver extensions to Marketplace quickly and more consistently using Azure Pipelines.

Thats it for this post - Thanks for reading this long post and I hope you found this post useful.

About author
Utkarsh Shigihalli
Utkarsh Shigihalli
Utkarsh is passionate about software development and has experience in the areas of Azure, Azure DevOps, C# and TypeScript. Over the years he has worked as an architect, independent consultant and manager in many countries including India, United States, Netherlands and United Kingdom. He is a Microsoft MVP and has developed numerous extensions for Visual Studio, Visual Studio Code and Azure DevOps.
We Are
  • onlyutkarsh
    Utkarsh Shigihalli
    Microsoft MVP, Technologist & DevOps Coach

  • arora_tarun
    Tarun Arora
    Microsoft MVP, Author & DevOps Coach at Avanade

Do you like our posts? Subscribe to our newsletter!
Our Book