coreybutler / node-windows

Windows support for Node.JS scripts (daemons, eventlog, UAC, etc).
Other
2.79k stars 358 forks source link

Service is not installing after compiling #245

Closed Tobias-Keller closed 4 years ago

Tobias-Keller commented 4 years ago

Hi! I have written a Electron.js app where i want to generate dynamically windows services. this works very well on my dev machine. The app requests for permission to create the service and installs it smoothly.

My Problem If i compile the app to an exe the app doesnt request me for permissions and print an error

Permission Denied. Requires administrative privileges.

The app creates the service exe successfully at that time and doesnt do anything more.

Ok, so i started the app with admin privileges for testing this behavior. Nice, the app doesnt show any error, creates the service exe AND ahhhhhh installed the service NOT.

Why does the app no ​​longer ask for permissions when it is compiled? Why isn't the service installed when the app is compiled? (Tested the exe on my dev machine, so vue is installed)

coreybutler commented 4 years ago

I'm not clear what you mean when referring to the service being installed when the "app is compiled". When Electron is compiled?

The most likely reason for seeing differing behavior is a service conflict. If an attempt is made to install a service when it already exists, it merely exits... it does not overwrite an installation.

It could also be that Electron needs to request elevated permissions, instead of node-windows. In other words, the user account which is executing the process needs to be "conditioned" before node-windows can do its job.

If all of that fails, you should be able to run node-windows in a detached child process. Electron may still run that child process under the same user context, but it may not suppress the prompts.

Tobias-Keller commented 4 years ago

example 1: if i run my electron app with npm start, i can install and uninstall a service with node-windows a prompt (4 times) for admin permissions ist displayed while the installation of the service

example 2:

example 3:

If all of that fails, you should be able to run node-windows in a detached child process. Electron may still run that child process under the same user context, but it may not suppress the prompts.

have you an example?

Edit: the events "invalidinstallation and alreadyinstalled" not firing, so i think there is not this problem.

Tobias-Keller commented 4 years ago

the created service.exe in the daemon folder can be successfully installed via cmd with path/to/daemon/service.exe install so the steps to create the service exe works in compiled status. (if programm runs as administrator)

if i run this from the electron developers tool in the installed electron app i can install the service as administrator: const {execSync} = require('child_process'); execSync('C:\\Users\\...\\service.exe install');

coreybutler commented 4 years ago

See https://nodejs.org/dist/latest-v12.x/docs/api/child_process.html#child_process_options_detached for detached processes.

If it works from the electron devtools, then it's working within the rendering process (as opposed to the main process). It sounds like the user context/permissions are being manipulated within Electron's main process (I just don't know what those manipulations are). You may want to wrap the installation process in a try/catch, writing any errors to a log file. I'd also suggest testing the file system permissions (i.e. fs.accessSync) to make sure the process can write to the appropriate directory from the main process and execute the service.exe file.

Tobias-Keller commented 4 years ago

i tested it with a try/catch, this prints no error. I debuged in node-windows functions and the install method goes throug with no errors. But the execute function in daemon.js (line520) executes the install command and fires the install event without having realy installed the service and without checking on errors.

The install event also runs through without errors. The execute on line 649 must give an error, because the service is not installed. But it have no errors, why? The same exec in a windows cmd gives a error.

after some more debugging i found an error in child_process.js. They say "the system cant find the path", the value is the following cmd command: ""C:\Users\Tobias\AppData\Local\Programs\my-software\resources\app.asar\node_modules\node-windows\bin\elevate\elevate.cmd" "C:\Users\Tobias\AppData\Local\Programs\my-software\daemon\service.exe" install"

in the first path there is a "app.asar" electron package file, maybe the command line cant open files in this package. The same folder with a other name is unpacked in the same folder.

do you now where the first path is defined? Maybe i can replace "app.asar" with "app.asar.unpacked" in this path before executing?

Tobias-Keller commented 4 years ago

day 3: figured out that the path is defined in the binaries.js on line 44. For testing pupose i hardcoded the real path and nice, the app installs the service! the app requests no also the admin privilegs if i start the app as normal user.

So the real problem is the composition of the path when executing the command. Here the command line simply cannot open the path of the Asar file or cannot look into it.

The electron packager also makes the files of the "node-windows" available unpacked. This path is accessible for the cmd, so maybe you should simply insert a switch for electron applications here.

the asar path we get from the process.argv and adding the path to the elevate.cmd file grafik

The next problem is, that the createt service daemon is in the asar package and the cmd command cant execute it to install, if the script is not at the root directory of your software. but this is not windows-node, this are packinging problems...

Tobias-Keller commented 4 years ago

got this done but the service is not launching the service script... found that in the service.xml file the executable is the packaged app exe...

if i changed this to "node_modules/electron/dist/electron.exe" executable from the unpacked app it runs. But in the packaged app this file is not present and with the new generated executable it is not running. So i think we cant get the node context from the packaged app executable.

If we change the executable in the xml config to the global node executable, the service runs.

Some possible solutions:

*notice: why i am writing this here and not in blog? :-) maybe someone need this

coreybutler commented 4 years ago

Thanks for detailing your journey. I'm sure others will find this useful. If you're OK with it, I'll link to this issue from the wiki.

In my personal experience with Electron, I wound up writing my own installer to distribute specific files outside of the asar file (and modify them at install time if necessary). It is possible to execute Electron as though it were "just node", and you can find the path using OS tools like "where" (Win32) and "which" (macOS).

Tobias-Keller commented 4 years ago

Since I wanted a software that also runs on operating systems that do not have node installed and it does not work via the finished electron app executable, I have included the pure electron binary file in the directory. I can run the services via this like it is a "just note" application.

and yes, i edit the xml config file after creating the services programmatically (changed the executable path to the path of the electron binary).

if you want you can link this of course to the wiki.

coreybutler commented 4 years ago

https://github.com/coreybutler/node-windows/wiki :)

zhangxu924 commented 3 years ago

got this done but the service is not launching the service script... found that in the service.xml file the executable is the packaged app exe...

if i changed this to "node_modules/electron/dist/electron.exe" executable from the unpacked app it runs. But in the packaged app this file is not present and with the new generated executable it is not running. So i think we cant get the node context from the packaged app executable.

If we change the executable in the xml config to the global node executable, the service runs.

Some possible solutions:

  • find a way to get the node.exe path on the machine (if it is installed)
  • copy the electron modul dist folder to your package and edit the service config programmatically
  • find a solution to use your app executable that i didnt found

*notice: why i am writing this here and not in blog? :-) maybe someone need this

@coreybutler @Tobias-Keller I found this thread very useful. Thanks a lot for the work you've done. But now the problem is the electron.exe binary is huge in size (approximately 100 MB). It makes the distribution of our software painful. So did you guys found a more elegant way to reuse the node runtime that Electron App uses?

Tobias-Keller commented 3 years ago

So did you guys found a more elegant way to reuse the node runtime that Electron App uses?

I haven't found a better way. A other way that was in my mind was do add the node.js setup to the app, and install it while setup the app. But we won't install node.js on all machines.

If you find a better way, I would be happy if you share it here.

arjun-singh-in2it commented 3 years ago

Hello Tobias-Keller,Hope you are doing well. I also want to achieve same. I have electron app which starts a service. The scenirio is - When i use npm start , it creates a exe and installed it as service and run it fine. But when i create build of electron app - service installs , but does not start because may be it not finds server.js file or node .

Tobias-Keller commented 3 years ago

But when i create build of electron app - service installs , but does not start because may be it not finds server.js file or node .

It's because you have not disabled asar. Electron will package your app files as asar file and Node cant use the files inside the asar file. So disable asar and use the correct path

arjun-singh-in2it commented 3 years ago

.

So disable asar and use the correct path

Thanks for your quick reply. I managed to start service with below code-

service = new Service({ name: 'nodecustomtestsvc1', description: 'A simple node js server', script: 'C:\Program Files\Electron Test\resources\app\server.js', execPath: 'C:\Program Files\nodejs\node.exe', env: { name: 'HOME', value: process.env['USERPROFILE'] } });

But you can see i am passing path of node.js. So could you help me that how can i run this service where node,js is not installed.

yuapple commented 2 years ago

@Tobias-Keller i can't start service in the electron , but i can start node example, can you show me your code , it bothers me

yuapple commented 2 years ago

@coreybutler how are the scripts run, i dont see any use in the source code

tomasantunes commented 1 year ago

I'd like to add that you can use a subprocess in your electron app to run a node script that starts the service with node-windows. As long as you can package NodeJS into your app.