Sunday 25 January 2015

Installing a Service using Topshelf with OctopusDeploy

I was using OctopusDeploy to install a Rebus service endpoint as a Windows Service from a console application created using Topshelf.

Octopus has built-in support for Windows Services that uses sc.exe under the hood.  I'd used this many times previously without hitch, but for some reason the install seemed to start before the service was fully removed.  As Topshelf can do all the service set up, I decided to try using that instead.

My deployment step in Octopus was configured to use the standalone PowerShell scripts.  Installing using Topshelf is simple - just call the executable using the commandline install --autostart.  Removing a Topshelf service is just as simple - call the executable using the uninstall commandline.

The only hard part is finding the executable path for the service so that you can remove the service before re-deploying.  PowerShell doesn't have built-in support for this at time of writing, but you can do that pretty easily using WMI.  The following function is based on David Martin's SO answer and finds the executable path from the service name:

From that point, it's pretty easy to remove the service using Topshelf:

An alternative approach would be to use a known installation location each time and derive the executable path using Octopus' powerful variables.

The code for the pre-deployment and  post-deployment tasks can be found in this gist.
The full Topshelf command line reference is here.


Anonymous said...


We include a PreDeploy.ps1 and PostDeploy.ps1 script in the package with the following content:

& ./NAME_OF_EXE.exe stop | Write-Host
& ./NAME_OF_EXE.exe uninstall | Write-Host

& ./NAME_OF_EXE.exe install | Write-Host
& ./NAME_OF_EXE.exe start | Write-Host

See below for more information:

Sean Kearon said...

That's another way to do it. I've always preferred to put the scripts into Octopus so as to keep as many of the the deployment concerns in one place.

Note that using predeploy.ps1 as you suggest presumes the install location to be the same as the previous. In which case that would work fine in either predeploy.ps1 or in Octopus.

Unknown said...

I think you can run PreDeploy from Octopus.Tentacle.PreviousInstallation.OriginalInstalledPath and it will do uninstallation properly.
When you do service removal from Octopus script, you force your Octopus project to know the service name, this means you can't just change in your Topshelf code only, you always have to remember to fix it in Octopus too.

Unknown said...

Thanks for this, helped me a lot :)

Chris McKenzie said...

Great idea. Have you considered putting this in the community library?

Sean Kearon said...

Thanks @Chris, that's a great idea. Will do that!