Azure DevOps to build office (Visio) VSTO Add-ins

These notes basically summarize setting up automated build for Office extensions (such as VSTO) in the cloud (i.e. Azure DevOps). Note that Azure DevOps supports private repositories for free. For open source repositories, it does not even impose any limitations (for private repositories, max build time per month is limited, so you cannot occupy 100% of the server for your builds). Basically I’m fine with "free" layer for now.


My motivation was to do builds and installers not on my developer machine, but to have this process automated. Microsoft provides cool build services named Azure DevOps. It can build using several technologies right out of the box. I’ll try to show my experience with moving build SvgExport (and other my extensions) to Azure Pipelines. My goal was: I edit the code, then I could click one button, and the new version of the extension is build and published on my website for the users to download. No More compiling manual build on local computer, no updating versions, no manual releases on GitHub, no manual signing, no FTP uploads to the hosting.

The pieces

  • I use GitHub to store the source code. Azure DevOps has out-of-the box integration with it.

  • I build using Visual Studio. DevOps can build using Visual Studio. This is pretty straightforward (the only tricky part is related to code signing certificates, see below in details).

  • I use WiX (Windows Installer Xml) to build the installers. This one is also supported on DevOps out of the box (i.e. it is preinstalled). Since most of my Visio extension are based on the Visio Addin Project Template this works fine.

  • I sign my installers using my own code signing certificate. This is covered with custom scripts and "Secure Files" and "Secure Variables" azure features.

  • I have versioning for the releases. This is basically all custom.. I’ve written a PowerShell script that does all these things with versioning for me – the good thing is that you can do basically whatever you want with it on DevOps.

  • Finally, I want to deploy some files as a release to GitHub and to the website with FTP. Please note that the source code is also stored on GitHub, now it gives you free repositories for both commercial (limited) and free (unlimited) projects.

This is how the steps to build the extension look:


I use "vs2017-win2016" image to build (Windows 2016 and Visual Studio 2017). Simply building the release configuration of the solution. It has VSTO (Visual Tools for Office) already installed.


VSTO (Visual Studio Tools for Office) signing wants the certificate to be available on the build machine during the build. This is a bit tricky in the cloud (especially if you have an open-source project) but can be done. You can store the certificate in "secure files", and the password in "secure variables" not available to anybody except admin group for example. And during the build apply the certificate (it’s wiped out after build anyways). Please see the build script (at the end) for the details.


Basically building installer is pretty much straightforward; you have WiX pre-installed on that build machine. Please note that to workaround occasional hanging of the build, you may need to add parameter to MSBuild: /p:RunWixToolsOutOfProc=true. See the related discussion on the StackOverflow.

The code

The current open-source project under development is set has open-source build as well. Please note that it’s already migrated to the new yaml pipeline. Now you have a choice of using "classic" pipelines or store the whole build project in yaml file. I have migrated most of the projects already to yaml pipelines, because they allow you to easily reuse them and track any changes.

GitHub: HtmlSidebar

Azure DevOps: HtmlSidebar Pipeline

If you would like to hear more details, please check the above projects, or comment.


    1. nbelyh

      You can check out the build file on GitHub, it’s in YML file (there are no other settings), i.e. it’s a “modern” pipeline with yml:

      The only hidden thing there should be the certificate itself and the username/password
      Feel free to ping me directly with email/linkedin also 🙂

      The only thing that’s not there is the certificate file itself (it’s a file uploaded to “secure stoage” and called “sectigo.pfx”) and the password for that file, that is coming from a “secure variable” $(CertPass) + hash to identifiy that certificate $(CertSha)

Leave a Reply