-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPowerShellSshClient.ts
135 lines (121 loc) · 5.19 KB
/
PowerShellSshClient.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { Client, ConnectConfig } from 'ssh2';
var _disconnected = false;
export class PowerShellSSHClient {
private readonly client: Client;
constructor(private readonly config: ConnectConfig, private readonly pwsh: string = "pwsh") {
this.client = new Client();
}
async executeScript(scriptPath: string, scriptArguments: string): Promise<string> {
console.log("### SSH Tunnel - Executing script:" + scriptPath);
const conn = await this.connect();
console.log("### SSH Tunnel - Retrieving remote temp folder");
var remoteTempFolder = await this.sendCommand('echo %temp%', conn);
remoteTempFolder = remoteTempFolder.trim();
console.log("### SSH Tunnel - Remote temp folder: " + remoteTempFolder);
var remoteScriptPath = String.prototype.concat(remoteTempFolder, '\\HyperVServer.ps1');
console.log("### SSH Tunnel - Remote script path: " + remoteScriptPath);
await this.uploadFile(conn, scriptPath, remoteScriptPath);
// we need to upload the logging lib into ps folder because of relative paths which are different in PS-Mode
var remoteLogScriptPath = String.prototype.concat(remoteTempFolder, '\\Logging.ps1');
console.log("### SSH Tunnel - Remote script path: " + remoteLogScriptPath);
// figure out the logging lib path based on the script path
var path = require('path');
var scriptFileName = path.basename(scriptPath);
scriptFileName = scriptFileName.substring(0, scriptFileName.length - 4);
var logScriptPath = scriptPath.replace(scriptFileName, "Logging");
await this.uploadFile(conn, logScriptPath, remoteLogScriptPath);
var result = await this.sendCommand(`${this.pwsh} -File ${remoteScriptPath} ${scriptArguments}`, conn);
result = result.trim();
//console.log("### SSH Tunnel - Script result: ");
//console.log(result);
await this.disconnect(conn);
console.log("### SSH Tunnel - Script executed");
return result;
}
private async connect(): Promise<Client> {
return new Promise((resolve, reject) => {
this.client
.on('ready', () => {
console.log("### SSH Tunnel - Connection ready");
resolve(this.client);
})
.on('error', (err) => {
if (!_disconnected) {
console.log("### SSH Tunnel - Connection error");
console.log(err);
reject(err);
}
})
/*.on('keyboard-interactive', function (this: any, name, descr, lang, prompts, finish) {
console.log("### SSH Tunnel - Warning: KEYBOARD INTERACTIVE is used. It's not secure.");
var password = this.config.password;
return finish([password])
})*/
.connect(this.config);
_disconnected = false;
console.log("### SSH Tunnel - Connected");
});
}
async uploadFile(conn: Client, localPath: string, remotePath: string): Promise<void> {
await new Promise<void>((resolve, reject) => {
conn.sftp((err, sftp) => {
console.log("### SSH Tunnel - Initiating SFTP connection");
if (err) {
console.log("### SSH Tunnel - SFTP connection error");
reject(err);
}
console.log("### SSH Tunnel - SFTP connection established");
console.log("### SSH Tunnel - Uploading file " + localPath + " to " + remotePath);
sftp.fastPut(localPath, remotePath, {}, (err) => {
if (err) {
console.log("### SSH Tunnel - File upload error");
reject(err);
}
console.log("### SSH Tunnel - File uploaded");
resolve();
});
});
}
);
}
private async sendCommand(command: string, conn: Client): Promise<string> {
return new Promise((resolve, reject) => {
console.log("### SSH Tunnel - Trying to execute command: " + command);
conn.exec(command, (err, stream) => {
if (err) {
console.log("### SSH Tunnel - Command error");
this.disconnect(conn);
reject(err);
}
console.log("### SSH Tunnel - Command executing");
var result = '';
stream
.on('close', (code: any, signal: any) => {
console.log("### SSH Tunnel - Command executed");
if (code != undefined && Number.parseInt(code) !== 0) {
console.log("### SSH Tunnel - Error executing command via PowerShell. Exit code: " + code + " Signal: " + signal);
reject("Error executing command via PowerShell. Exit code:" + code + " Signal:" + signal);
}
console.log("### SSH Tunnel - Successfull executed script via PowerShell. Exit code:" + code + " signal:" + signal);
resolve(result);
})
.on('data', (data: string) => {
result += data.toString().trim();
console.log(data.toString().trim());
})
.stderr.on('data', (data) => {
console.log('(SSH-Error) ' + data.toString().trim());
//reject(data.toString().trim());
});
});
});
}
private async disconnect(conn: Client): Promise<void> {
return new Promise((resolve, reject) => {
console.log("### SSH Tunnel - Disconnecting");
conn.end();
_disconnected = true;
console.log("### SSH Tunnel - Disconnected");
});
}
}