rannn505 / child-shell

Node.js bindings 🔗 for shell
http://rannn505.github.io/child-shell/
MIT License
301 stars 71 forks source link

Powershell files cannot be found/executed when packaged (pkg) inside exe #106

Closed KingKarrow closed 4 years ago

KingKarrow commented 4 years ago

Hello, I found an issue that I haven't been able to get around. I want to use npm pkg (https://www.npmjs.com/package/pkg) to bundle my code into an easy executable and keep clients from seeing the source. Unfortunately, though I've enjoyed working with this module to launch my Powershell scripts, I don't think it works as well inside a pkg'd project.

Here is a simple "ps.js", which uses node-powershell to run my Powershell script:

var path = require('path');
var fs = require('fs');
var shell = require('node-powershell');

console.log(__dirname);
console.log(fs.readdirSync(__dirname));
var ps = new shell({
  executionPolicy: 'Bypass',
  noProfile: true
});
ps.addCommand('. ' + path.join(__dirname, 'start.ps1'));
ps.invoke()
.then(output => {
  console.log('v---start.ps1---v');
  console.log(output);
  console.log('^---start.ps1---^');
})
.catch(err => {
  console.log('v---start.ps1 [errors]---v');
  console.log(err);
  console.log('^---start.ps1 [errors]---^');
  ps.dispose();
});

// give me time to read the exe's output before it closes
setTimeout(function() {
    console.log('exiting!');
}, 5000);

.... and "start.ps1":

Write-Output 'start.ps1 has been executed'

Running node ps.js from a Powershell window works fine, returning the following output:

D:\Programs\git\ps-proj
[
  '.git',            '.gitignore',
  'ps.js',       'start.ps1',
]
v---start.ps1---v
start.ps1 has been executed

^---start.ps1---^

I then run the pkg command: pkg ps.js --output ps.exe , and run ps.exe ; The exe version will break. Here is the output:

D:\snapshot\ps-proj
[ 'ps.js', 'start.ps1', 'node_modules' ]
v---start.ps1 [errors]---v
PS_CMD_FAIL_ERROR:
      . : The term 'D:\snapshot\ps-proj\start.ps1' is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
and try again.
At line:1 char:3
+ . D:\snapshot\ps-proj\start.ps1
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (D:\snapshot\ps-proj\start.ps1:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    at ShellStreamBuffer.<anonymous> (D:\snapshot\ps-proj\node_modules\node-powershell\lib\Shell.js:220:25)
    at Object.onceWrapper (events.js:299:28)
    at ShellStreamBuffer.emit (events.js:210:5)
    at ShellStreamBuffer._write (D:\snapshot\ps-proj\node_modules\node-powershell\lib\utils.js:27:19)
    at doWrite (_stream_writable.js:431:12)
    at writeOrBuffer (_stream_writable.js:415:5)
    at ShellStreamBuffer.Writable.write (_stream_writable.js:305:11)
    at Socket.ondata (_stream_readable.js:727:22)
    at Socket.emit (events.js:210:5)
    at addChunk (_stream_readable.js:309:12) {
  name: 'PS_CMD_FAIL_ERROR'
}
^---start.ps1 [errors]---^

So... am I doing something wrong? Is there a different way to run/reference scripts? Because I only saw the possibility of using addCommand. Or, is it just not possible to call a script while inside pkg?

KingKarrow commented 4 years ago

Hello again! I was able to solve this. It turns out, the issue is pretty universal across different packaging modules: once packaged inside the exe, you can only reference internal files with the fs commands! So basically, you're only going to get scripts read in as big strings. My next issue was figuring out how to call them. It took a while to get one thing to work consistently, but here's what I ended up with:

...
var startStr = fs.readFileSync(path.join(__dirname, 'start.ps1')).toString();
ps.addCommand('& {' + startStr + '} \n');
...

Note: The \n is very important, because without it the command fails to fire and it just hangs. Also, here is an example with an argument (because addArgument would not work here):

...
var arg1 = 14;
var startStr = fs.readFileSync(path.join(__dirname, 'start.ps1')).toString();
ps.addCommand('& {' + startStr + '} ' + arg1 + '\n');
...

So that's it! I have .ps1 files successfully hidden away inside my exe, and still being executed.