I am working with node.js, and I am trying to embed a console in the web browser to work in a remote server. The web application do the connection so the user does not need to do the ssh username#host but only type commands.
I have tried the node.js' ssh2 module and other modules which use ssh2. But I'm experiencing always the same problem. Every time I execute a command programmatically using exec(), the ssh session is restarted. I'll explain it better with an example.
> ls
returns the content of home directory, one of the directories in the home directory is mydir
> cd mydir
> ls
returns the content of my home directory again, because after a command is executed the ssh session is closed/restarted.
Any node.js library which can do the job? or even a library of other technology different to javascript?
Edit: Other example for clarifying, using the node.js' module ssh-exec
The server has to execute some commands in other machine using ssh. A function in the server contains the following code
var c = exec.connection('username#host.com'); // It takes the ssh key from the default location
exec('cd mydir', c).pipe(process.stdout);
exec('ls -lh', c).pipe(process.stdout);
As you can see I am not ending the connection after the first exec but the output I obtain is the content of the home directory not the content of mydir directory, because the ssh session is reset after each exec.
The maintainer of node.js' ssh2 module provided the solution.
To use the method shell() instead of the method exec().
The method shell() creates an interactive session with the server we are connecting.
The method shell() provides a stream as a parameter of its callback (like the method exec()).
Like when using exec(), stream.on('data', function(data, extended) {...}); can be used to get the output of the commands. However, in this case, to provide commands (input) to the machine you connected with, you need to use stream.write(yourcommand+'\n');
PS. Feel free to edit to improve the accuracy of the answer.
I have to guess a bit, but you do something like child = exec('ssh username#host ls')?
You can do something like
child = exec('ssh username#host');
upfront and in the "loop" of your browser
child.stdin.write('ls\n');
When finished, just close stdin:
child.stdin.end()
which also finishes the child process.
I know this link is old but I figured this may help someone if they're looking for a solution. The
To use the method shell() instead of the method exec().
Works. Here's another solution. Use absolute file paths i.e.
conn.exec("mkdir -p /home/user/Direc/{one,two,three}/", function(err, stream) {
if (err) throw err;
stream.on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
});
conn.exec("ls -la /home/user/", function(err, stream) {
if (err) throw err;
stream.on('close', function(code, signal) {
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
});
Related
I have a bash script that I am running server side from meteor. I have tested that I am successfully able to run shell commands by running 'ls' and getting the expected response back. However, when I run my shell script no output is ever logged to the server console and none of the intended effects of the script are successful. I am printing stderr,stdout, and error yet they print nothing when I run my script.
Meteor.methods({
grade: function(unittest, code) {
this.unblock();
var sys = Npm.require('sys');
var exec = Npm.require('child_process').exec;
// exec('/bin/ls /srv/srcalyzer/scripts', function(error,stdout,stderr){
// console.log('error: ',error);
// console.log('stdout: ',stdout);
// console.log('stderr: ',stderr);
// });
console.log('running grade')
exec('/bin/bash /srv/srcalyzer/scripts/grade.sh', function(error,stdout,stderr){
console.log('error: ',error);
console.log('stdout: ',stdout);
console.log('stderr: ',stderr);
});
console.log('just finished.');
},
Although it is currently commented out the /bin/ls /some/path logs the expected output to console. However when I run the /bin/bash /path/to/.sh that I know is in place. The console output looks like
I20161207-15:22:07.031(-5)? running grade
I20161207-15:22:07.045(-5)? just finished.
The script does take a short time to run (~15-20 seconds). I am uncertain if this is relevant or not.
Can someone please help me understand what is happening?
there's a hint here:
I20161207-15:22:07.031(-5)? running grade
I20161207-15:22:07.045(-5)? just finished.
that's only taking a few ms to run. meaning, your Meteor method is likely exiting before the exec() finishes. i've never run an exec() in Meteor, so i'm unsure if that shell script keeps running after your method exits.
what you need is to run a future in your Meteor method, so it doesn't exit until your shell script comes back.
something like:
let future = new Future();
exec('/bin/bash /srv/srcalyzer/scripts/grade.sh', function(error,stdout,stderr){
console.log('error: ',error);
console.log('stdout: ',stdout);
console.log('stderr: ',stderr);
future.return(stdout.toString());
});
return future.wait();
now your Meteor method will wait until your script finishes.
(caveat: i didn't try this, just typing this solution from memory on my non-work machine)
I am trying to run a powershell command through a nodejs script. I have found the following two articles which have shown me something similar to what I am trying to acheive:
Execute Windows Commands with Nodejs
Execute powershell script from nodejs
On a button click event, I am trying to list the usb devices currently attached to the system along with its Drive Letter (C, D, E etc). If I run the command in the powershell on its own, it works (I am unable to get it to display the drive letter though). However, if I run it as part of my script it does not work. Below is my code:
if (process.platform === 'win32' || process.platform === 'win64') {
exec("powershell.exe",["GET-WMIOBJECT win32_diskdrive | Where { $_.InterfaceType –eq 'USB' }"], function (err, stdout, stderr) {
console.log(err);
console.log(stdout);
console.log(stderr);
});
}
What am I doing wrong?
You can use Node-PowerShell.
Node-PowerShell taking advantage of two of the simplest, effective and easy tools that exist in the today technology world. On the one hand, NodeJS which made a revolution in the world of javascript, and on the other hand, PowerShell which recently came out with an initial open-source, cross-platform version, and by connecting them together, gives you the power to create any solution you were asked to, no matter if you are a programmer, an IT or a DevOps guy.
Another way...
exec('command here', {'shell':'powershell.exe'}, (error, stdout, stderr)=> {
// do whatever with stdout
})
I believe you shold pass the code with -command before it. Default PowerShell syntax is: powershell.exe -command "get-wmiobject ...".
Something like this:
exec("powershell.exe",["-command \"Get-WmiObject -Class win32_diskdrive | Where { $_.InterfaceType -eq 'USB' }\""], function (err, stdout, stderr) {
console.log(err);
console.log(stdout);
console.log(stderr);
});
You'll want to request child_process with..
var exec = require("child_process").exec;
Then you'll want to call exec() to execute a child process, followed by the commands you want the child process to execute, you'll need to do this with a callback function as well as seen in the snippet below, you need this to catch errors in case something goes wrong and you need to fix it.
exec('CommandHere', {'shell':'powershell.exe'}, (error, stderr, stdout) => {
if (error !== null) {
// Do something
}
});
Here's an example using Powershell's set-location and gci commands to search recursively for a file within a specified directory and return it's relative path for Windows...
var exec = require("child_process").exec;
var folder = "C:\\Users\\winUser\\just\\some\\folder\\location";
var file = "test.txt";
exec('set-location ' + '"' + folder + '"' +
';' + ' gci -path ' + '"' + folder + '"' +
' -recurse -filter ' + '"' + file + '"' +
' -file | resolve-path relative',
{'shell':'powershell.exe'}, (error, stderr, stdout) => {
var filePath = stdout.substring(stdout.indexOf(".\\") + 2).trim("\n");
if (error !== null) {
console.log("Cannot locate the given file \n");
console.log(error);
}
console.log("File located! \n Path: " + filePath);
});
Hope this helps anyone facing this issue.
I have the following Node.js code to ssh into a server and it works great forwarding stdout, but whenever I type anything it is not forwarding to the server. How do I forward my local stdin to the ssh connections stdin?
var command = 'ssh -tt -i ' + keyPath + ' -o StrictHostKeyChecking=no ubuntu#' + hostIp;
var ssh = child_proc.exec(command, {
env: process.env
});
ssh.stdout.on('data', function (data) {
console.log(data.toString());
});
ssh.stderr.on('data', function (data) {
console.error(data.toString());
});
ssh.on('exit', function (code) {
process.exit(code);
});
There's two ways to go about this if you want to pipe the process.stdin to the child process:
Child processes have a stdin property that represents the stdin of the child process. So all you should need to do is add process.stdin.pipe(ssh.stdin)
You can specify a custom stdio when spawning the process to tell it what to use for the child process's stdin:
child_proc.exec(command, { env: process.env, stdio: [process.stdin, 'pipe', 'pipe'] })
Also, on a semi-related note, if you want to avoid spawning child processes and have more programmatic control over and/or have more lightweight ssh/sftp connections, there is the ssh2 module.
I'm trying to download a lot of files using nodejs and the exec command, simplified like this:
var cmd = 'wget -O output.csv URL';
var child = exec(cmd, function(err) {
console.log('DONE');
});
However, the callback is triggered before the file was actually downloaded through wget, leading to a file that contains garbage like '��0O�6D�1n�]v�����#�'. Shouldn't the callback be triggered once wget is done? When running the same command on the command line it takes rougly 5 seconds, since the file has several MB.
Btw: I'm not using the request module since it's slower and I ran into emitter listener issues (EventEmitter memory leak detected. 11 listeners added).
Thanks!
This will involve some debugging.
Can you please try running your script as:
var cmd = 'wget -O output.csv URL';
var child = exec(
cmd,
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
}
);
It would be interesting to see what stdout and stderr say.
Right, you provided me your stderr which said:
http://productdata.zanox.com/exportservice/v1/rest/22791753C32335607.csv?ticket=BC4B91472561713FD43BA766542E9240AFDD01B95B123E40B2C0375E3A68C142
This URL the command line gets is missing everything after the ampersand (& character). This indicates a problem with escaping.
To get around this try replacing \& with \\\&.
I have a server that's using TLS 1.0
It gives me an infinite stream of data on the terminal when the command
~$ openssl s_client -connect 'serveraddress':5000
This provides me with a realtime xml data stream of what my server is currently doing.
I want to connect to it using node.js or any other way that provides me with the possibility to push this data stream as a websocket or directly onto a JS, but I can't seem to figure out how. Can any of you please help?
Thanks :)
I think something like that should solve your problem.
var terminal = require('child_process').spawn('bash');
terminal.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
terminal.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
setTimeout(function() {
console.log('Sending stdin to terminal');
terminal.stdin.write("openssl s_client -connect 'serveraddress':5000");
terminal.stdin.end();
}, 1000);
Edit:
Try this for a working example:
terminal.stdin.write("ping www.google.de");