Search code examples
node.jswindows-installer

Run MSI package from nodejs app


I would like to run mongoDB MSI package from nodeJS application. I tried to follow the answer to this question but it gives me following error:

internal/child_process.js:298
throw errnoException(err, 'spawn');
^
Error: spawn UNKNOWN
    at exports._errnoException (util.js:837:11)
    at ChildProcess.spawn (internal/child_process.js:298:11)
    at exports.spawn (child_process.js:339:9)
    at exports.execFile (child_process.js:141:15)
    at C:\_PROJECTs\nodejs\automation\mongoDB-setup\auto-setup.js:34:5
    at C:\_PROJECTs\nodejs\automation\mongoDB-setup\lib\file.js:31:5
    at C:\_PROJECTs\nodejs\automation\mongoDB-setup\lib\file.js:20:5
    at FSReqWrap.oncomplete (fs.js:82:15)

When trying simple EXE file (e.g. puttygen.exe) it works.

Here is the relevant part of code I have:

'use strict'
const os = require('os'),
      path = require('path'),
      setup = require('child_process').execFile;

const fileName = 'mongodb.msi';
//const fileName = 'puttygen.exe';
const dest = path.join(os.homedir(), fileName);

// run the installation
setup(dest, function(err, data) {  
  console.log(err);                      
});

I am not sure whether execFile is the correct way for MSI packages as well.


Solution

  • I would suggest to use spawn instead in this case. (see node js documentation for more explanation). On win64 I think you need to spawn command line with parameters, otherwise child_process.js will do it for you (same for unix).

    Here is an example of your case (NOT ES6):

    var os = require('os'),
      path = require('path'),
      setup = require('child_process').spawn;
    
    //1)uncomment following if you want to redirect standard output and error from the process to files
    /*
    var fs = require('fs');
    var out = fs.openSync('./out.log', 'a');
    var err = fs.openSync('./out.log', 'a');
    */
    var fileName = 'mongodb.msi';
    
    //spawn command line (cmd as first param to spawn)
    var child = spawn('cmd', ["/S /C " + fileName], { // /S strips quotes and /C executes the runnable file (node way)
      detached: true, //see node docs to see what it does
      cwd: os.homedir(), //current working directory where the command line is going to be spawned and the file is also located
      env: process.env
      //1) uncomment following if you want to "redirect" standard output and error from the process to files
      //stdio: ['ignore', out, err]
    });
    
    //2) uncomment following if you want to "react" somehow to standard output and error from the process
    /*
    child.stdout.on('data', function(data) {
      console.log("stdout: " + data);
    });
    
    child.stderr.on('data', function(data) {
      console.log("stdout: " + data);
    });
    */
    
    //here you can "react" when the spawned process ends
    child.on('close', function(code) {
      console.log("Child process exited with code " + code);
    });
    
    // THIS IS TAKEN FROM NODE JS DOCS
    // By default, the parent will wait for the detached child to exit.
    // To prevent the parent from waiting for a given child, use the child.unref() method,
    // and the parent's event loop will not include the child in its reference count.
    child.unref();
    

    Hope it helps :) If you want win32 or UNIX version it will look a little bit different, look at the docs again for more, or post another request. Also see source code for child_process.js.