7

I want to check programmatically that the latest version of my Windows Service is installed. I have:

var ctl = ServiceController.GetServices().Where(s => s.ServiceName == "MyService").FirstOrDefault();
if (ctl != null) {
  // now what?
}

I don't see anything on the ServiceController interface that will tell me the version number. How do I do it?

Shaul Behr
  • 36,951
  • 69
  • 249
  • 387

3 Answers3

12

I am afraid there is no way other than getting the executable path from the registry as ServiceController does not provide that information.

Here is a sample I had created before:

private static string GetExecutablePathForService(string serviceName, RegistryView registryView, bool throwErrorIfNonExisting)
    {
        string registryPath = @"SYSTEM\CurrentControlSet\Services\" + serviceName;
        RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView).OpenSubKey(registryPath);
        if(key==null)
        {
            if (throwErrorIfNonExisting)
                throw new ArgumentException("Non-existent service: " + serviceName, "serviceName");
            else
                return null;
        }
        string value = key.GetValue("ImagePath").ToString();
        key.Close();
        if(value.StartsWith("\""))
        {
            value = Regex.Match(value, "\"([^\"]+)\"").Groups[1].Value;
        }

        return Environment.ExpandEnvironmentVariables(value);
    }

After getting the exe path, just use FileVersionInfo.GetVersionInfo(exePath) class to get the version.

Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • +1 Thanks! How do you compare a `FileVersionInfo` to the `Version` object you get back from `Assembly.GetAssembly(...).GetName().Version`? – Shaul Behr Dec 29 '10 at 15:52
  • 2
    That should give you FileVersion while the one you mentioned is the AssemblyVersion. If you need AssemblyVersion, then you have to load it as an assembly (as you mentioned). But **BEWARE** once you have loaded it, you have locked the file (even if you load as ReflectionOnly) until your process terminates. – Aliostad Dec 29 '10 at 16:01
  • I'm curious what the Regex is doing here? I get that "if the value starts with a quote, then ..." It seems to strip leading and trailing quotes off -- same as value = value.Trim(new[] { '"' }); would do .. but it is doing something else as well? – ckittel Jan 26 '12 at 18:46
  • 1
    @ckittel It trims it. But the normal trim does not work since the value has soemething at the end: `"c:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Binn\sqlservr.exe" -sMSSQLSERVER` – Aliostad Jan 27 '12 at 13:47
  • That makes perfect sense, thanks. I wasn't thinking of command-line args. – ckittel Jan 27 '12 at 14:20
2

If you own the service, you can put version information into the DisplayName, e.g. DisplayName="MyService 2017.06.28.1517". This allows you to find an existing installation of your service and parse the version information:

var ctl = ServiceController
    .GetServices()
    .FirstOrDefault(s => s.ServiceName == "MyService");
if (ctl != null) {
    // get version substring, you might have your own style.
    string substr = s.DisplayName.SubString("MyService".Length);
    Version installedVersion = new Version(substr);
    // do stuff, e.g. check if installed version is newer than current assembly.
}

This may be useful if you want to avoid the registry. The problem is, that service entries can go to different parts of the registry depending on the installation routine.

Patrick Stalph
  • 792
  • 1
  • 9
  • 19
0

If you are talking about getting the current version of your service automatically from the assembly properties then you can set up a property such as below in your ServiceBase class.

public static string ServiceVersion { get; private set; }

Then in your OnStart method add the following...

ServiceVersion = typeof(Program).Assembly.GetName().Version.ToString();

Full Example

using System.Diagnostics;
using System.ServiceProcess;

public partial class VaultServerUtilities : ServiceBase
{

    public static string ServiceVersion { get; private set; }

    public VaultServerUtilities()
    {
        InitializeComponent();

        VSUEventLog = new EventLog();
        if (!EventLog.SourceExists("Vault Server Utilities"))
        {
            EventLog.CreateEventSource("Vault Server Utilities", "Service Log");
        }

        VSUEventLog.Source = "Vault Server Utilities";
        VSUEventLog.Log = "Service Log";

    }


    protected override void OnStart(string[] args)
    {

        ServiceVersion = typeof(Program).Assembly.GetName().Version.ToString();
        VSUEventLog.WriteEntry(string.Format("Vault Server Utilities v{0} has started successfully.", ServiceVersion));

    }

    protected override void OnStop()
    {
        VSUEventLog.WriteEntry(string.Format("Vault Server Utilities v{0} has be shutdown.", ServiceVersion));
    }
}

In the example above my event log displays the current version of my service... enter image description here

Fütemire
  • 1,705
  • 1
  • 26
  • 21