5

All the solutions I can find on this topic are very old and none of them appear to answer my question...

I am trying to create a windows service that can self update (or auto update by some external trigger). In the past, I had created a windows service that was installed with InstallShield and we were able to update auto update the service in a hacky way by making the service write a batch script to the local machine and then run the batch script, which would stop the service, overwrite the service executable and other files with the new ones, and restart the service. This surprisingly worked.

However, I have updated the service to use InstallUtil.exe and this auto update script no longer works... I assume it's something to do with the way InstallShield handles the service install vs how InstallUtil does it... but I can only make guesses as I don't fully understand what each is doing to the registry.

Since I can't just overwrite the files and restart the service with the InstallUtil method, I thought I'd write a batch script that runs sc.exe to stop the service, uninstall it entirely, write the new files, install the new service files, and then start it... unfortunately, I can't seem to get sc.exe to run from a windows service automatically because it requires admin permissions... I tried to force it to self-elevate to admin using this snippet, but it doesn't appear to work as a service (it works fine if I run it from command line not as a service)

if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)

Does anyone know how I can cause a windows service to self update? I can look into updating to a .NET Core Worker service if there is some method of self update in .NET Core that I'm unaware of... Any ideas are much appreciated... it really shouldn't be this hard to accomplish...

For reference, here is the batch script I am currently using (ignore odd variables and such as I am dynamically replacing some of them, it works great when launched manually, just doesn't work when the service tries to run it):

@echo off
setlocal enableextensions enabledelayedexpansion


::make sure to run whole script as admin (this restarts scripts as admin if not already in admin mode)
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
pushd %networkDirectory%

::stop running service
for /F "tokens=3 delims=: " %%H in ('sc query %serviceName% ^| findstr "        STATE"') do (
    if /I "%%H" NEQ "STOPPED" (
        net stop %serviceName%
        if errorlevel 1 goto :stop
    )

    ::delete existing service after stopping
    sc delete %serviceName%
)

:: install updated service files
set "releaseDir=%networkDirectory%\Release"
set "programFilesCopyDir=%ProgramFiles%\{_companyDirectory}\%serviceName%\Release"

:: copy service Release dir to local system program files
xcopy "%releaseDir%" "%programFilesCopyDir%" /S /Y /Q

::execute the install
pushd "%programFilesCopyDir%"
CALL %serviceName%.exe --install

::start service
sc start %serviceName%
eerick
  • 411
  • 3
  • 16
  • Does this answer your question? [Best practice for writing a self-updating windows service](https://stackoverflow.com/questions/1608228/best-practice-for-writing-a-self-updating-windows-service) as well as [I want my C# Windows Service to automatically update itself](https://stackoverflow.com/questions/106765/i-want-my-c-sharp-windows-service-to-automatically-update-itself) – Pavel Anikhouski May 19 '20 at 07:40
  • Having a little bit of consulting and sysadmin experience on my shoulders: Are you 100% positively sure, you _need_ to update automatically and you _can_ do so without problems to production systems? As Sysadmin, I would do anything within my powers to prevent an auto-updating service to be installed. – Fildor May 19 '20 at 07:46
  • @Fildor, technically it doesn't auto-update... we only push updates when we have vetted them, but it does need to be self-updating as the service runs on 50+ different machines and it's a PITA to update them all manually when we have updates – eerick May 19 '20 at 07:47
  • Ah, so it is _you_ providing dev _and_ ops ... ok. Have you been trying out installer tools like [WiX](https://wixtoolset.org/) ? – Fildor May 19 '20 at 07:50
  • @PavelAnikhouski, unfortunately I have poured over those links already in the past few days looking for solutions and they do suggest a batch script much the same as I've already been doing, but those suggestions are 10+ years old at this point and they just don't work on newer versions of windows (likely due to security settings changes) – eerick May 19 '20 at 07:50
  • @Fildor, I have not attempted using WIX for this purpose... I was under the impression WIX functioned similarly to InstallShield. Does it not just create the installer? Or are you saying it resides on the system and can accept further communication pushed to it after an install? Does that not then require managing another service? I'll do some reading on WIX and see if it might meet my needs. – eerick May 19 '20 at 07:58
  • It can stop, uninstall , update, install, start the service. Checking if a new version is available and downloading the new installer - I would make that a different task. Maybe a little program or script that can be triggered by Windows Task Scheduler ... – Fildor May 19 '20 at 08:00
  • 1
    @eerick you can try to use MSI/WIX for that, [this](https://stackoverflow.com/questions/7395609/what-is-the-best-way-to-auto-update-a-windows-application) thread as starting point. Clickonce also have such possibility, look [here](https://stackoverflow.com/questions/12787761/how-to-automatically-update-an-application-without-clickonce). Finally you can try something AutoUpdater.NET – Pavel Anikhouski May 19 '20 at 08:00
  • 1
    FWIW I *have* written a self-updating service; it worked by running the real code in an app-domain - it could pull down newer versions into a side directory, spin up a new app-domain, and switch over to that (releasing the old), and the main thing I learned from this was: **don't do it** - just get better at how you update services. There are lots of tools for automated orchestrated server updates, including services. Use them. "Puppet", perhaps. – Marc Gravell May 19 '20 at 08:36

1 Answers1

5

For anyone else trying to accomplish this that stumbles on this... I ended up finding a solution. I use the same script posted in my question above, but I wrote code to set up a scheduled task with Windows Task Scheduler. The scheduled task runs the above script as a one time scheduled task. This works like a charm.

I used this NuGet package to write the Task Scheduler code I needed: https://www.nuget.org/packages/TaskScheduler/2.8.20?_src=template

eerick
  • 411
  • 3
  • 16