3

I'm working on an application that will run as a windows service, and I'm trying to get it to update itself automatically.


My current approach is to to execute a powershell script, which will stop the service, run a msi installer, and then restart the service.

This is what the powershell script looks like at this time

Start-Sleep -s 10
Write-Host "update start"
Stop-Service ServiceName1
msiexec /i c:\ProgramData\ProgramName\Install\ServiceName.Setup.msi /passive /l*v C:\ProgramData\ProgramName\Install\log.txt | Out-Null
Start-Service ServiceName1
Write-Host "update finished"

This is how I'm running it from the app

Process.Start("Powershell", @"C:\ProgramData\ProgramName\Install\UpdateApp.ps1");

What happens, is the service stops and restarts, but it doesn't update. It's as though the msi never gets run. The log file doesn't even appear.

When I run the Service as a command line app from an elevated command prompt it works as expected and the app gets updated, so My current theory is that the service isn't running the powershell script with administrator privileges.

Other questions suggest that I set up the log on settings for the service to use an administrator account, so I set the service to run as the account that I was currently logged in under, who was able to open an elevated command prompt and/or manually run the installer, but doing that didn't change anything.


Is there any way to do what I'm trying to do?

I'm currently not committed to any particular automatic update strategy, but I do know that I want this service to update itself. So if I'm doing something completely wrong, I'm 100% open to attempting a different approach.


UPDATE:

I made the following change to log the error and output for msiexecc

Try{
    c:\windows\system32\msiexec.exe /i c:\ProgramData\ProgramName\Install\ServiceName.msi /passive /l*v C:\ProgramData\ProgramName\Install\log.txt | Out-File -filepath C:\ProgramData\ProgramName\Install\output.txt
}
Catch {
    $_ | Out-File C:\ProgramData\ProgramName\Install\errors.txt -Append
}

After running that script, I found the following error:

The term 'msiexec' is not recognized as the name of a cmdlet, function, script file, or operable program..

Community
  • 1
  • 1
  • @stuartd If I could find a solution to this problem with a quick google search, I wouldn't be asking a question here in the first place. – Sam I am says Reinstate Monica Mar 08 '16 at 17:26
  • @stuartd So I've started the windows service as the built in .\Administrator account, and there has been no change – Sam I am says Reinstate Monica Mar 08 '16 at 17:38
  • Is the service configured with restricted privileges? (You can use `sc qsidtype` to find out if you're not sure.) – Harry Johnston Mar 08 '16 at 20:55
  • @HarryJohnston sorry for the delay, I had to focus on a different project for a few days. `sc qsidtype programName`, gives me `SERVICE_NAME: programName` and `SERVICE_SID_TYPE: NONE` – Sam I am says Reinstate Monica Mar 14 '16 at 19:05
  • 1
    Better narrow the problem down, I think. Try Process Monitor (available free of charge from the MS web site) to see whether the Powershell process is getting launched at all, whether the msiexec process is getting launched, whether the Powershell process is dying prematurely, etc. – Harry Johnston Mar 14 '16 at 19:58
  • @HarryJohnston Process Monitor captures a lot of stuff. When I filter out everything but process and thread activity, I can see that Powershell is getting started, but I can't find anything about msiexec. when I don't filter, there is too much information to make sense of. – Sam I am says Reinstate Monica Mar 14 '16 at 20:27
  • My guess is that when you stop the service, Powershell is stopping too. That doesn't *usually* happen for children of services IIRC, but perhaps either Process.Start(), the .NET classes that implement application services, or Powershell is doing something unusual. I suggest you start by changing the script to one that waits 30 seconds and then exits, and make sure you can see that happening as expected in Process Monitor. Then you can change it so it waits 5s, stops the service, waits 30s, then exits, and see how long it runs for. If my theory is right it will exit after about 5s. – Harry Johnston Mar 14 '16 at 20:37
  • Another guess: perhaps Powershell doesn't like you using Write-Host when it doesn't have an interactive console to display the text on. – Harry Johnston Mar 14 '16 at 20:39
  • @HarryJohnston I'm pretty sure powershell is not stopping when the service is stopping, because it's successfully starting the service back up again – Sam I am says Reinstate Monica Mar 14 '16 at 20:46
  • @HarryJohnston additionally, when I run the service from an elevated command prompt instead of as a service, the powershell script and installer run as expected. I do see windows for both powershell and the installer appear when this happens, so when this happens, so that doesn't rule out the no-interactive-console theory yet. – Sam I am says Reinstate Monica Mar 14 '16 at 20:48
  • Gah. I completely missed that, sorry. Wild goose chase then. Perhaps get the Powershell script to check the return code for msiexec? And perhaps capture any output rather than routing it to Out-Null. – Harry Johnston Mar 14 '16 at 20:49
  • @HarryJohnston I did that, and the result was `The term 'msiexec' is not recognized as the name of a cmdlet, function, script file, or operable program.`. What i did was I changed `msiexec` to `c:\windows\system32\msiexec.exe`, and that worked. Since it was your good sense that got me to that point, If you post that as an answer, I'll mark it as a solution. – Sam I am says Reinstate Monica Mar 14 '16 at 22:24

1 Answers1

1

It looks like the call to msiexec isn't actually targeting c:\windows\system32\msiexec.exe

As per this question it seems that Powershell does not use the standard PATH environment variable, but has its own scheme, which perhaps doesn't work as expected in the context of a system service.

The simplest resolution, as you say, is to specify the full path, which is probably c:\windows\system32\msiexec.exe.

However, in production, it would probably be wise to avoid the use of a hardcoded path, since you might run into problems with localization, operating system changes, and so on. You could perhaps use SearchPath or a .NET equivalent from your service and either write out the Powershell script in real time or pass the path to msiexec as a command-line option, or there may be a sensible Powershell solution.

Community
  • 1
  • 1
Harry Johnston
  • 33,445
  • 6
  • 56
  • 142