how to have a windows service self update? - c#

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%

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

Related

How to Run a Batch File in a Windows Service with an API and Debug it?

I am attempting to run a batch file that utilizes the VMWare VIX API and VMRun.exe to power on/off virtual machines in VMWare Workstation. Currently my batch files work correctly when run from the command prompt. However, I can not successfully execute them from my Windows Service built in C# & .NET. I executed my batch files in my service in the following way:
string myBatchFile = ConfigurationManager.AppSettings.Get("MyBatchFile");
System.Diagnostics.ProcessStartInfo processBat = new System.Diagnostics.ProcessStartInfo(myBatchFile);
processBat.WindowStyle = ProcessWindowStyle.Normal;
processBat.ErrorDialog = true;
Process.Start(processBat);
I have been able to run a simple batch file that creates a text document from the service. The code for this batch file looks like this:
#echo off
echo Hello World>"C:\Users\MyPC\Documents\HelloWorld.txt"
This works as expected when executed by my Windows Service.
When I try to execute my VMWare batch file I am unsuccessful, and can not find any way to check log my output or debug it. My code for this batch file looks like this:
#echo off
set LOGFILE=batch.log
call :LOG > %LOGFILE%
exit /B
:LOG
cd "C:\PROGRA~2\VMware\VMWARE~2\"
vmrun.exe -T ws Start "C:\Users\MyPC\Documents\Virtual Machines\VM1\VM1.vmx"
PAUSE
I attempted to add a way for a log file to be created but nothing gets generated when I execute the batch file from the service. Any guidance would be greatly appreciated, thank you.

msiexec uninstall from c# fails to stop service

I have a service that runs and accepts remote commands. I am trying to send a remote command to uninstall. This works and executes the msiexec. The msiexec gets to the point where it tries to stop the service and then hangs and eventually fails saying no privileges to stop the service.
If I run the same command from a command window it works fine.
I have tried this running the service as local system (with admin privs) as well as administrator (I enabled the administrator account)
I just can't seem to figure out why I am getting permission errors stopping the service running the msiexec
added information
We have a single service - it does required work and sleeps periodically
the service typically runs as local system
we have the installer set using custom actions - and all cases work fine - installing and uninstalling from command line - but running msiexec uninstaller initiated within the C# code has this issue
When a remote request is made to uninstall the desire is to remove the service, registry entries, and files on disk
The request is handled by the running service - it goes to the registry, finds the product entry and retrieves the uninstall command
when the uninstall is performed I use C# process and include in the StartInfo parameters the program name, arguments, and verb (defined as run as) - among other parameters
the uninstaller starts properly, does some actions, and then gets to the point of stopping the service
stopping the service sits until it times out after which it writes in the uninstall log that there may not be sufficient privileges to stop the service
The note from Quercus triggered the solution to my problem. It turns out changing to not run the uninstall as a child of the service allowed the uninstaller to perform the msiexec without issue. To accomplish this I had to change UseShellExecute from false to true.

Systemd service using 100% of my CPU when start as service and it doesn't if I start it without systemd

I'm using Ubuntu with the latest updates. I made a systemd service to run a script (Server.exe) (Mono, C#) when my server starts. Here's its configuration:
[Unit]
Description=My
After=network.target
[Service]
PIDFile=/home/my/server/bshserver.pid
WorkingDirectory=/home/my/server
ExecStart=/home/my/server/start
User=my
Group=my
SyslogIdentifier=My-Server
StandardOutput=syslog
Restart=on-failure
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target
"start" file:
#!/bin/sh
echo Starting MyServer in /home/my/server
/home/my/server/Server.exe
exit $?
I was to try another Ubuntu, fail too
When I run the script /home/my/server/start normally (simply /home/my/server/start on my terminal), it is working as expected. Top reports it's using between 2 and, say, 5% of my CPU, which is normal.
But when I start it with service start, htop says it's always using at least 100% of my CPU (one core)
What could explain such a big difference in CPU usage?
There are a couple issues I'm seeing:
In order to start a mono application it must be run with the command mono. Use which mono to find the full path of mono installed on your server. As it is your script will report a failure every time its run.
Your systemd configuration has OnRestart=on-failure set, which is working more effectively than intended. Since your script will always fail systemd will continuously try to restart the service.
Update your script to include calling mono:
#!/bin/sh
echo Starting MyServer in /home/my/server
/user/bin/mono /home/my/server/Server.exe
exit $?
If your service uses ServiceBase then use:
#!/bin/sh
echo Starting MyServer in /home/my/server
/user/bin/mono-service /home/my/server/Server.exe
exit $?
Your script may imply that Server.exe will fork. Add Type=forking to your configuration.
[Unit]
Description=My
After=network.target
[Service]
Type=forking
PIDFile=/home/my/server/bshserver.pid
WorkingDirectory=/home/my/server
ExecStart=/home/my/server/start
User=my
Group=my
SyslogIdentifier=My-Server
StandardOutput=syslog
Restart=on-failure
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target

Asp.Net Core - Error cannot execute binary file on published (Ubuntu 14.04) web application with supervisor

I am not sure if this is the right place to ask, but here it is: I created an ASP.NET Core web application, and copied all the files on my Ubuntu 14.04 server. I can compile and run without a problem, but now I want this application/web site to run permanently.
I followed all the steps described here https://docs.asp.net/en/latest/publishing/linuxproduction.html, installed nginx as reverse proxy to run with apache, and all of this run perfectly well.
BUT, trying to use supervisor and start the app from it, I systematically get an error /usr/bin/dotnet cannot execute binary file. But, if I move to be in the directory where the application is published, and manually type dotnet appname.dll it does start without a glitch.
I am not sure where to look to get this to work with supervisor. Thanks for your help (and if this question should be somewhere else, let me know)
I finally solved my problem, replacing the equivalent of the line command=bash /usr/bin/dotnet /var/aspnetcore/HelloMVC/HelloMVC.dll as described in https://docs.asp.net/en/latest/publishing/linuxproduction.html under "Configuring Supervisor" by a little script, far from perfect as I get a Warning: HOME environment variable not set.
Anyway, here is the script:
#!/bin/bash
cd /var/aspnetcore/foesuivi/
dotnet FoESuivi.dll
cd $HOME
As a windows programmer, I don't know much about bash scripting, but I certainly can see that I would need to give a value to $HOME before the cd command.
Anyway, after doing a chmod +x to the sh file, and replacing the command= with the full name of the sh file, it is now working, I can reboot and my site is immediately available.

Installing C# Windows Service on Windows 7

I have a batch file that I have been using to install my C# Windows Services for awhile now, never had a problem until Windows 7. I have attempted to run the batch file with Administrator privileges. I have attempted to run the command prompt with admin privs, navigate to the windows service EXE and run InstallUtil there. Still doesn't work.
After reading some other suggestions I tried moving my files out of the /bin folder and running them from another location but that also didn't work.
The batch file looks like this
#ECHO OFF
REM The following directory is for .NET 2.0
set DOTNETFX2=%SystemRoot%\Microsoft.NET\Framework\v2.0.50727
set PATH=%PATH%;%DOTNETFX2%
echo Installing IEPPAMS Win Service...
echo ---------------------------------------------------
InstallUtil /i IEPPAMS_WinService1.exe
echo ---------------------------------------------------
echo Done.
and I have a install log file that I dump info to. If I just double click the .bat file I get
Running a transacted installation.
Beginning the Install phase of the
installation. See the contents of the
log file for the
C:\Users\Justin\Desktop\service
test\IEPPAMS_WinService1.exe
assembly's progress. The file is
located at
C:\Users\Justin\Desktop\service
test\IEPPAMS_WinService1.InstallLog.
An exception occurred during the
Install phase.
System.InvalidOperationException:
Cannot open Service Control Manager on
computer '.'. This operation might
require other privileges. The inner
exception
System.ComponentModel.Win32Exception
was thrown with the following error
message: Access is denied.
The Rollback phase of the installation
is beginning. See the contents of the
log file for the
C:\Users\Justin\Desktop\service
test\IEPPAMS_WinService1.exe
assembly's progress. The file is
located at
C:\Users\Justin\Desktop\service
test\IEPPAMS_WinService1.InstallLog.
The Rollback phase completed
successfully.
The transacted install has completed.
When I run the .bat file with admin privileges nothing is written to the log file, and the service is still not installed.
Any thoughts? Is there a new way to install services in Windows 7?
Right click on the batch file and run it as Administrator.
You are most likely running into battle with the new security model (User Account Control) from Windows Vista and Windows 7. Even if you are running as an account that has Admin rights you will still need to elevate to do some (most) administrative activities. (Yes it is possible to disable this feature, but don't)
UAC (MSDN)
UAC (Wikipedia)
InstallUtil (MSDN)
Edit... The correct commandline is InstallUtil YourApp.exe. The /i does not look to be a vaild switch for InstallUtil.
So I was able to fix the problem by typing in the command line the entire path to InstallUtil and it worked. So after navigating to the folder that had my EXE I typed the following:
C:\Windows\Microsoft.NET\Framework\v4.0.21006\installutil.exe
IEPPAMS_WinService1.exe
Not sure why I have to do that in Windows 7 now when I never had to in XP, but oh well. Thanks for all the suggestions!
When I run the .bat file with admin privileges nothing is written to the log file, and the service is still not installed.
First off, you HAVE to run as admin permissions.
Second, when you "Run as Administrator", it actually changes the directory to c:\windows\system32 as the initial directory ( no idea why ), which would probably explain why running as admin causes no log file. Manually change to the path IEPPAMS_WinService1.exe resides in that the start of your script.

Categories

Resources