2

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.

Community
  • 1
  • 1
mauretanec
  • 23
  • 5

4 Answers4

1
const dest = "cmd /c " + path.join(os.homedir(), fileName);
zamuka
  • 796
  • 2
  • 9
  • 21
  • I am sorry, but I don't get it. What should that change accomplish? I got following error when trying that: `[Error: spawn cmd /cC:\Users\bulavjan\mongodb.msi ENOENT] code: 'ENOENT', errno: 'ENOENT', syscall: 'spawn cmd /cC:\\Users\\bulavjan\\mongodb.msi', path: 'cmd /cC:\\Users\\bulavjan\\mongodb.msi', spawnargs: [], cmd: 'cmd /cC:\\Users\\bulavjan\\mongodb.msi'` – mauretanec Feb 13 '16 at 14:55
  • You've missed the space character after /c – zamuka Feb 14 '16 at 18:27
  • True :). Now I have: `const dest = "cmd /c " + path.join(os.homedir(), fileName);` but the result is still the same: `[Error: spawn cmd /c C:\Users\bulavjan\mongodb.msi ENOENT]`. – mauretanec Feb 15 '16 at 08:17
  • Your msi file might be downloaded from web and not yet unlocked. Find the .msi packet in browser, Right click on it and then press the "Unblock" button on the bottom of "General tab". – zamuka Feb 15 '16 at 10:23
1

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.

luzas
  • 36
  • 3
0

The best way to run .msi files is to use a command line tool provisioned with windows knows as msiexec. So the code snipped will be the following

import * as os from 'os';
import { spawn } from 'child_process';

// /quiet does installing in background process. Use docs to find more. 
export const runMSI = (msiName: string, args?: string[]) => {
    const childProcess = spawn('msiexec', [`/i ${msiName} /quiet`], {
        detached: false,
        cwd: os.homedir(),
    });

    childProcess.stdout.on('data', (data) => {
        console.log('STDOUT: ', data.toString());
    });

    childProcess.stderr.on('data', (data) => {
        console.log('STDERR: ', data.toString());
    });


    childProcess.on('close', (code: number) => {
        console.log('Child exited with code ' + code);
    });
};
Ayzrian
  • 2,279
  • 1
  • 7
  • 14
0

i come from the futrue>> 2020-jul-29. nodejs docs recommend using exec and execFile functions instead.

For convenience, the child_process module provides a handful of synchronous and asynchronous alternatives to child_process.spawn() and child_process.spawnSync(). Each of these alternatives are implemented on top of child_process.spawn() or child_process.spawnSync(). https://nodejs.org/api/child_process.html#child_process_spawning_bat_and_cmd_files_on_windows

mustafa
  • 89
  • 7