@netcuras/nodejs-winrm 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +15 -0
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/azure-pipelines.yml +20 -0
- package/eslint.config.js +31 -0
- package/examples/test.js +13 -0
- package/index.js +48 -0
- package/package.json +54 -0
- package/src/base-request.js +81 -0
- package/src/command.js +208 -0
- package/src/enumerate.js +213 -0
- package/src/http.js +82 -0
- package/src/invoke.js +42 -0
- package/src/shell.js +87 -0
- package/src/util.js +20 -0
- package/test/test.js +13 -0
package/.travis.yml
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Shone
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# nodejs-winrm
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/nodejs-winrm)
|
|
4
|
+
[](https://travis-ci.org/shoneslab/nodejs-winrm)
|
|
5
|
+
[](https://dev.azure.com/SHONEJACOB/SHONEJACOB/_build/latest?definitionId=1?branchName=master)
|
|
6
|
+
|
|
7
|
+
nodejs-winrm is a NodeJS client to access WinRM (Windows Remote Management) SOAP web service. It allows to execute commands on target windows machines.
|
|
8
|
+
Please visit [Microsoft's WinRM site](http://msdn.microsoft.com/en-us/library/aa384426.aspx) for WINRM details.
|
|
9
|
+
|
|
10
|
+
## Supported NodeJS Versions
|
|
11
|
+
|
|
12
|
+
Tested on NodeJS Version > 8.11
|
|
13
|
+
|
|
14
|
+
## Supported WinRM Versions
|
|
15
|
+
|
|
16
|
+
As of now Winrm Version 3 is tested.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
> winrm id
|
|
20
|
+
|
|
21
|
+
IdentifyResponse
|
|
22
|
+
ProtocolVersion = http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
|
|
23
|
+
ProductVendor = Microsoft Corporation
|
|
24
|
+
ProductVersion = OS: 10.0.xxxx SP: 0.0 Stack: 3.0
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
On the remote host, a PowerShell prompt, using the __Run as Administrator__ option and paste in the following lines:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
> winrm quickconfig
|
|
33
|
+
y
|
|
34
|
+
> winrm set winrm/config/service/Auth '@{Basic="true"}'
|
|
35
|
+
> winrm set winrm/config/service '@{AllowUnencrypted="true"}'
|
|
36
|
+
> winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}'
|
|
37
|
+
```
|
|
38
|
+
On the client side where NodeJS is installed
|
|
39
|
+
|
|
40
|
+
`npm install nodejs-winrm`
|
|
41
|
+
|
|
42
|
+
## Examples
|
|
43
|
+
|
|
44
|
+
### Run a Single Command
|
|
45
|
+
```
|
|
46
|
+
var winrm = require('nodejs-winrm');
|
|
47
|
+
winrm.runCommand('mkdir D:\\winrmtest001', '10.xxx.xxx.xxx', 'username', 'password', 5985);
|
|
48
|
+
winrm.runCommand('ipconfig /all', '10.xxx.xxx.xxx', 'username', 'password', 5985);
|
|
49
|
+
```
|
|
50
|
+
### Run multiple Commands (Advanced)
|
|
51
|
+
```
|
|
52
|
+
var winrm = require('nodejs-winrm');
|
|
53
|
+
|
|
54
|
+
var userName = 'userName';
|
|
55
|
+
var password = 'password';
|
|
56
|
+
var _host = '10.xxx.xxx.xxx';
|
|
57
|
+
var _port = 5985;
|
|
58
|
+
|
|
59
|
+
var auth = 'Basic ' + Buffer.from(userName + ":" + password, 'utf8').toString('base64');
|
|
60
|
+
var params = {
|
|
61
|
+
host: _host,
|
|
62
|
+
port: _port,
|
|
63
|
+
path: '/wsman'
|
|
64
|
+
};
|
|
65
|
+
params['auth'] = auth;
|
|
66
|
+
|
|
67
|
+
//Get the Shell ID
|
|
68
|
+
params['shellId']= await winrm.shell.doCreateShell(params);
|
|
69
|
+
|
|
70
|
+
// Execute Command1
|
|
71
|
+
params['command'] = 'ipconfig /all';
|
|
72
|
+
params['commandId'] = await winrm.command.doExecuteCommand(params);
|
|
73
|
+
var result1= await winrm.command.doReceiveOutput(params);
|
|
74
|
+
|
|
75
|
+
// Execute Command2
|
|
76
|
+
params['command'] = 'mkdir D:\\winrmtest001';
|
|
77
|
+
params['commandId'] = await winrm.command.doExecuteCommand(params);
|
|
78
|
+
var result2= await winrm.command.doReceiveOutput(params);
|
|
79
|
+
|
|
80
|
+
// Close the Shell
|
|
81
|
+
await winrm.shell.doDeleteShell(params);
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
## Testing
|
|
87
|
+
|
|
88
|
+
`npm test`
|
|
89
|
+
|
|
90
|
+
## Maintainers
|
|
91
|
+
* Shone Jacob (https://github.com/shoneslab)
|
|
92
|
+
|
|
93
|
+
## Credits
|
|
94
|
+
* https://github.com/jacobludriks/winrmjs
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Node.js
|
|
2
|
+
# Build a general Node.js project with npm.
|
|
3
|
+
# Add steps that analyze code, save build artifacts, deploy, and more:
|
|
4
|
+
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
|
|
5
|
+
|
|
6
|
+
trigger:
|
|
7
|
+
- master
|
|
8
|
+
|
|
9
|
+
pool:
|
|
10
|
+
vmImage: 'Ubuntu-16.04'
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- task: NodeTool@0
|
|
14
|
+
inputs:
|
|
15
|
+
versionSpec: '8.x'
|
|
16
|
+
displayName: 'Install Node.js'
|
|
17
|
+
|
|
18
|
+
- script: |
|
|
19
|
+
npm install
|
|
20
|
+
displayName: 'npm install and build'
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const js = require('@eslint/js');
|
|
2
|
+
const globals = require('globals');
|
|
3
|
+
|
|
4
|
+
module.exports = [
|
|
5
|
+
{
|
|
6
|
+
ignores: ['coverage/**']
|
|
7
|
+
},
|
|
8
|
+
js.configs.recommended,
|
|
9
|
+
{
|
|
10
|
+
languageOptions: {
|
|
11
|
+
ecmaVersion: 2022,
|
|
12
|
+
sourceType: 'commonjs',
|
|
13
|
+
globals: {
|
|
14
|
+
...globals.node,
|
|
15
|
+
...globals.browser
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
rules: {
|
|
19
|
+
'no-console': 'off',
|
|
20
|
+
'linebreak-style': ['error', 'unix'],
|
|
21
|
+
quotes: ['error', 'single'],
|
|
22
|
+
semi: ['error', 'always']
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
files: ['test/**/*.spec.js', '__tests__/**/*.spec.js'],
|
|
27
|
+
languageOptions: {
|
|
28
|
+
globals: globals.jest
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
];
|
package/examples/test.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var winrm = require('../index.js');
|
|
2
|
+
|
|
3
|
+
async function performOneCommand() {
|
|
4
|
+
try {
|
|
5
|
+
//var result = await winrm.runCommand('mkdir D:\\winrmtest001', '10.xxx.xxx.xxx', 5985, 'username', 'password');
|
|
6
|
+
var result = await winrm.runCommand('ipconfig /all', '10.xxx.xxx.xxx', 'username', 'password', 5985);
|
|
7
|
+
console.log(result);
|
|
8
|
+
} catch (error) {
|
|
9
|
+
console.error(`Exception Occurred: ${error}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
performOneCommand();
|
package/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
let shell = require('./src/shell.js');
|
|
2
|
+
let command = require('./src/command.js');
|
|
3
|
+
let enumerate = require('./src/enumerate.js');
|
|
4
|
+
let invoke = require('./src/invoke.js');
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
shell: shell,
|
|
8
|
+
command: command,
|
|
9
|
+
enumerate: enumerate,
|
|
10
|
+
invoke: invoke
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
module.exports.runCommand = async function (_command, _host, _username, _password, _port, _usePowershell = false) {
|
|
14
|
+
try {
|
|
15
|
+
var auth = 'Basic ' + Buffer.from(_username + ':' + _password, 'utf8').toString('base64');
|
|
16
|
+
var params = {
|
|
17
|
+
host: _host,
|
|
18
|
+
port: _port,
|
|
19
|
+
path: '/wsman',
|
|
20
|
+
};
|
|
21
|
+
params['auth'] = auth;
|
|
22
|
+
var shellId = await shell.doCreateShell(params);
|
|
23
|
+
params['shellId'] = shellId;
|
|
24
|
+
|
|
25
|
+
params['command'] = _command;
|
|
26
|
+
var commandId;
|
|
27
|
+
if ( _usePowershell ) {
|
|
28
|
+
commandId = await command.doExecutePowershell(params);
|
|
29
|
+
} else {
|
|
30
|
+
commandId = await command.doExecuteCommand(params);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
params['commandId'] = commandId;
|
|
34
|
+
var output = await command.doReceiveOutput(params);
|
|
35
|
+
|
|
36
|
+
await shell.doDeleteShell(params);
|
|
37
|
+
|
|
38
|
+
return output;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.log('error', error);
|
|
41
|
+
return error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
module.exports.runPowershell = async function (_command, _host, _username, _password, _port) {
|
|
47
|
+
return module.exports.runCommand(_command, _host, _username, _password, _port, true);
|
|
48
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@netcuras/nodejs-winrm",
|
|
3
|
+
"version": "1.3.3",
|
|
4
|
+
"description": "Make WinRM service calls from NodeJS",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node ./test/test.js",
|
|
8
|
+
"outdated": "npm outdated --json || true",
|
|
9
|
+
"lint": "npx eslint .",
|
|
10
|
+
"jest:test": "jest",
|
|
11
|
+
"jest:coverage": "npx jest --coverage",
|
|
12
|
+
"jest:watch": "jest --watch"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/shoneslab/nodejs-winrm.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"winrm"
|
|
20
|
+
],
|
|
21
|
+
"author": "Shone Jacob",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/shoneslab/nodejs-winrm/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/shoneslab/nodejs-winrm#readme",
|
|
27
|
+
"jest": {
|
|
28
|
+
"automock": false,
|
|
29
|
+
"coveragePathIgnorePatterns": [],
|
|
30
|
+
"verbose": true,
|
|
31
|
+
"coverageReporters": [
|
|
32
|
+
"html",
|
|
33
|
+
"lcov",
|
|
34
|
+
"json",
|
|
35
|
+
"text",
|
|
36
|
+
"text-summary"
|
|
37
|
+
],
|
|
38
|
+
"testMatch": [
|
|
39
|
+
"<rootDir>/test/*.unit.spec.js",
|
|
40
|
+
"<rootDir>/__tests__/*.unit.spec.js"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"js2xmlparser": "^3.0.0",
|
|
45
|
+
"uuid": "^11.1.1",
|
|
46
|
+
"xml2js": "^0.6.2"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@eslint/js": "^10.0.1",
|
|
50
|
+
"eslint": "^10.7.0",
|
|
51
|
+
"globals": "^17.7.0",
|
|
52
|
+
"jest": "^30.4.2"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const { v5: uuidv5 } = require('uuid');
|
|
2
|
+
|
|
3
|
+
module.exports.getSoapHeaderRequest = function (_params) {
|
|
4
|
+
if (!_params['message_id']) _params['message_id'] = uuidv5.URL;
|
|
5
|
+
|
|
6
|
+
var header = {
|
|
7
|
+
'@': {
|
|
8
|
+
'xmlns:s': 'http://www.w3.org/2003/05/soap-envelope',
|
|
9
|
+
'xmlns:wsa': 'http://schemas.xmlsoap.org/ws/2004/08/addressing',
|
|
10
|
+
'xmlns:wsen': 'http://schemas.xmlsoap.org/ws/2004/09/enumeration',
|
|
11
|
+
'xmlns:wsman': 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd',
|
|
12
|
+
|
|
13
|
+
'xmlns:p': 'http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd',
|
|
14
|
+
'xmlns:rsp': 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell'
|
|
15
|
+
},
|
|
16
|
+
's:Header': {
|
|
17
|
+
'wsa:To': 'http://windows-host:5985/wsman',
|
|
18
|
+
|
|
19
|
+
'wsman:ResourceURI': {
|
|
20
|
+
'@': {
|
|
21
|
+
'mustUnderstand': 'true'
|
|
22
|
+
},
|
|
23
|
+
'#': _params['resource_uri'] || 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd'
|
|
24
|
+
},
|
|
25
|
+
'wsa:ReplyTo': {
|
|
26
|
+
'wsa:Address': {
|
|
27
|
+
'@': {
|
|
28
|
+
'mustUnderstand': 'true'
|
|
29
|
+
},
|
|
30
|
+
'#': 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
'wsman:MaxEnvelopeSize': {
|
|
34
|
+
'@': {
|
|
35
|
+
'mustUnderstand': 'true'
|
|
36
|
+
},
|
|
37
|
+
'#': '153600'
|
|
38
|
+
},
|
|
39
|
+
'wsa:MessageID': 'uuid:' + _params['message_id'],
|
|
40
|
+
'wsman:Locale': {
|
|
41
|
+
'@': {
|
|
42
|
+
'mustUnderstand': 'false',
|
|
43
|
+
'xml:lang': 'en-US'
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
'wsman:OperationTimeout': _params['operationTimeout'] || 'PT60S',
|
|
47
|
+
'wsa:Action': {
|
|
48
|
+
'@': {
|
|
49
|
+
'mustUnderstand': 'true'
|
|
50
|
+
},
|
|
51
|
+
'#': _params['action']
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
if (_params['shellId']) {
|
|
56
|
+
header['s:Header']['wsman:SelectorSet'] = [];
|
|
57
|
+
header['s:Header']['wsman:SelectorSet'].push({
|
|
58
|
+
'wsman:Selector': [{
|
|
59
|
+
'@': {
|
|
60
|
+
'Name': 'ShellId'
|
|
61
|
+
},
|
|
62
|
+
'#': _params['shellId']
|
|
63
|
+
}]
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (_params['selectorSet']) {
|
|
67
|
+
header['s:Header']['wsman:SelectorSet'] = [];
|
|
68
|
+
for (const [key, value] of Object.entries(_params['selectorSet'])) {
|
|
69
|
+
header['s:Header']['wsman:SelectorSet'].push({
|
|
70
|
+
'wsman:Selector': [{
|
|
71
|
+
'@': {
|
|
72
|
+
'Name': key
|
|
73
|
+
},
|
|
74
|
+
'#': value
|
|
75
|
+
}]
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return header;
|
|
81
|
+
};
|
package/src/command.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
const js2xmlparser = require('js2xmlparser');
|
|
2
|
+
let winrm_soap_req = require('./base-request.js');
|
|
3
|
+
let winrm_http_req = require('./http.js');
|
|
4
|
+
let util = require('./util.js');
|
|
5
|
+
|
|
6
|
+
function constructRunCommandRequest(_params) {
|
|
7
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
8
|
+
'action': 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command',
|
|
9
|
+
'shellId': _params.shellId,
|
|
10
|
+
'operationTimeout': _params.operationTimeout
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
res['s:Header']['wsman:OptionSet'] = [];
|
|
14
|
+
res['s:Header']['wsman:OptionSet'].push({
|
|
15
|
+
'wsman:Option': [{
|
|
16
|
+
'@': {
|
|
17
|
+
'Name': 'WINRS_CONSOLEMODE_STDIN'
|
|
18
|
+
},
|
|
19
|
+
'#': 'TRUE'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
'@': {
|
|
23
|
+
'Name': 'WINRS_SKIP_CMD_SHELL'
|
|
24
|
+
},
|
|
25
|
+
'#': 'FALSE'
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
res['s:Body'] = {
|
|
30
|
+
'rsp:CommandLine': {
|
|
31
|
+
'rsp:Command': _params.command
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function constructReceiveRequest(_params) {
|
|
38
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
39
|
+
'action': 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive',
|
|
40
|
+
'shellId': _params.shellId,
|
|
41
|
+
'operationTimeout': _params.operationTimeout
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
res['s:Body'] = {
|
|
45
|
+
'rsp:Receive': {
|
|
46
|
+
'rsp:DesiredStream': {
|
|
47
|
+
'@': {
|
|
48
|
+
'CommandId': _params.commandId
|
|
49
|
+
},
|
|
50
|
+
'#': 'stdout stderr'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function constructSignalRequest(_params) {
|
|
58
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
59
|
+
'action': 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal',
|
|
60
|
+
'shellId': _params.shellId,
|
|
61
|
+
'operationTimeout': _params.operationTimeout
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
res['s:Body'] = {
|
|
65
|
+
'rsp:Signal': [{
|
|
66
|
+
'@': {
|
|
67
|
+
'xmlns:rsp': 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell',
|
|
68
|
+
'CommandId': _params.commandId
|
|
69
|
+
},
|
|
70
|
+
'rsp:Code': `http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/${_params.signal || 'ctrl_c'}`
|
|
71
|
+
}]
|
|
72
|
+
};
|
|
73
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports.doExecuteCommand = async function (_params) {
|
|
77
|
+
var req = constructRunCommandRequest(_params);
|
|
78
|
+
|
|
79
|
+
var auth = _params.auth;
|
|
80
|
+
if (_params.authOnce) {
|
|
81
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
82
|
+
_params.auth = undefined;
|
|
83
|
+
_params.authOnce = undefined;
|
|
84
|
+
}
|
|
85
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
86
|
+
|
|
87
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
88
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
89
|
+
} else {
|
|
90
|
+
var commandId = result['s:Envelope']['s:Body'][0]['rsp:CommandResponse'][0]['rsp:CommandId'][0];
|
|
91
|
+
return commandId;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
function generatePowershellCommand(_params) {
|
|
96
|
+
var args = [];
|
|
97
|
+
args.unshift(
|
|
98
|
+
'powershell.exe',
|
|
99
|
+
'-NoProfile',
|
|
100
|
+
'-NonInteractive',
|
|
101
|
+
'-NoLogo',
|
|
102
|
+
'-ExecutionPolicy', 'Bypass',
|
|
103
|
+
'-InputFormat', 'Text',
|
|
104
|
+
'-Command', '"& {',
|
|
105
|
+
_params.command,
|
|
106
|
+
'; exit $LASTEXITCODE}"'
|
|
107
|
+
);
|
|
108
|
+
return args.join(' ');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports.doExecutePowershell = async function (_params) {
|
|
112
|
+
_params['command'] = generatePowershellCommand(_params);
|
|
113
|
+
return this.doExecuteCommand(_params);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
module.exports.doReceive = async function (_params) {
|
|
117
|
+
var req = constructReceiveRequest(_params);
|
|
118
|
+
|
|
119
|
+
var auth = _params.auth;
|
|
120
|
+
if (_params.authOnce) {
|
|
121
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
122
|
+
_params.auth = undefined;
|
|
123
|
+
_params.authOnce = undefined;
|
|
124
|
+
}
|
|
125
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
126
|
+
|
|
127
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
128
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
129
|
+
} else {
|
|
130
|
+
let response = {
|
|
131
|
+
commandState: undefined,
|
|
132
|
+
exitCode: undefined,
|
|
133
|
+
streams: []
|
|
134
|
+
};
|
|
135
|
+
if (result['s:Envelope']['s:Body'][0]['rsp:ReceiveResponse'][0]['rsp:Stream']) {
|
|
136
|
+
for (let stream of result['s:Envelope']['s:Body'][0]['rsp:ReceiveResponse'][0]['rsp:Stream']) {
|
|
137
|
+
let streamOutput = {};
|
|
138
|
+
streamOutput.name = stream['$'].Name;
|
|
139
|
+
if (Object.prototype.hasOwnProperty.call(stream['$'], 'End')) {
|
|
140
|
+
streamOutput.end = true;
|
|
141
|
+
} else if (stream['_']) {
|
|
142
|
+
streamOutput.data = Buffer.from(stream['_'], 'base64').toString('ascii');
|
|
143
|
+
}
|
|
144
|
+
response.streams.push(streamOutput);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (result['s:Envelope']['s:Body'][0]['rsp:ReceiveResponse'][0]['rsp:CommandState']) {
|
|
149
|
+
let commandStateResponse = result['s:Envelope']['s:Body'][0]['rsp:ReceiveResponse'][0]['rsp:CommandState'][0];
|
|
150
|
+
response.commandState = (commandStateResponse['$'].State || '').match(/\/([a-zA-Z0-9]+)$/)[1];
|
|
151
|
+
response.exitCode = commandStateResponse['rsp:ExitCode'] && commandStateResponse['rsp:ExitCode'][0];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// NOTE: for use with doReceiveOutput (set here for consistency), use returned response.commandState/response.exitCode when available
|
|
155
|
+
_params.commandState = response.commandState;
|
|
156
|
+
_params.exitCode = response.exitCode;
|
|
157
|
+
|
|
158
|
+
return response;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
module.exports.doReceiveOutput = async function (_params) {
|
|
163
|
+
let response = await module.exports.doReceive(_params);
|
|
164
|
+
if (response instanceof Error) {
|
|
165
|
+
return response;
|
|
166
|
+
}
|
|
167
|
+
let successOutput = '';
|
|
168
|
+
let failedOutput = '';
|
|
169
|
+
for (let stream of response.streams) {
|
|
170
|
+
if (stream.name === 'stdout' && !stream.end) {
|
|
171
|
+
successOutput += stream.data;
|
|
172
|
+
}
|
|
173
|
+
if (stream.name == 'stderr' && !stream.end) {
|
|
174
|
+
failedOutput += stream.data;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (successOutput) {
|
|
178
|
+
return successOutput.trim();
|
|
179
|
+
}
|
|
180
|
+
return failedOutput.trim();
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
module.exports.doSignal = async function (_params) {
|
|
184
|
+
var req = constructSignalRequest(_params);
|
|
185
|
+
|
|
186
|
+
var auth = _params.auth;
|
|
187
|
+
if (_params.authOnce) {
|
|
188
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
189
|
+
_params.auth = undefined;
|
|
190
|
+
_params.authOnce = undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
194
|
+
|
|
195
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
196
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
197
|
+
} else {
|
|
198
|
+
return result['s:Envelope']['s:Body'][0]['rsp:SignalResponse'][0];
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
module.exports.doSignalInterrupt = async function (_params) {
|
|
203
|
+
return module.exports.doSignal(Object.assign({}, _params, { signal: 'ctrl_c' }));
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
module.exports.doSignalTerminate = async function (_params) {
|
|
207
|
+
return module.exports.doSignal(Object.assign({}, _params, { signal: 'terminate' }));
|
|
208
|
+
};
|
package/src/enumerate.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
const js2xmlparser = require('js2xmlparser');
|
|
2
|
+
let winrm_soap_req = require('./base-request.js');
|
|
3
|
+
let winrm_http_req = require('./http.js');
|
|
4
|
+
let util = require('./util.js');
|
|
5
|
+
|
|
6
|
+
function constructBeginEnumerationRequest(_params) {
|
|
7
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
8
|
+
'resource_uri': _params.resourceUri || 'http://schemas.dmtf.org/wbem/wscim/1/*',
|
|
9
|
+
'action': 'http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate',
|
|
10
|
+
'selectorSet': _params.selectorSet,
|
|
11
|
+
'operationTimeout': _params.operationTimeout
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
res['s:Body'] = {
|
|
15
|
+
'wsen:Enumerate': [{
|
|
16
|
+
'wsen:NewContext': {},
|
|
17
|
+
'wsman:OptimizeEnumeration': [{}],
|
|
18
|
+
'wsen:MaxTime': _params.maxTime || 'PT60S',
|
|
19
|
+
'wsman:MaxElements': _params.maxElements || 20
|
|
20
|
+
}]
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (_params.filter) {
|
|
24
|
+
res['s:Body']['wsen:Enumerate'][0]['wsman:Filter'] = [{
|
|
25
|
+
'@': {
|
|
26
|
+
'Dialect': _params.filterDialect || 'http://www.w3.org/TR/1999/REC-xpath-19991116'
|
|
27
|
+
},
|
|
28
|
+
'#': _params.filter
|
|
29
|
+
}];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function constructPullEnumerationRequest(_params) {
|
|
36
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
37
|
+
'resource_uri': _params.resourceUri || 'http://schemas.dmtf.org/wbem/wscim/1/*',
|
|
38
|
+
'action': 'http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull',
|
|
39
|
+
'operationTimeout': _params.operationTimeout
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
res['s:Body'] = {
|
|
43
|
+
'wsen:Pull': [{
|
|
44
|
+
'wsen:EnumerationContext': _params.enumerationId,
|
|
45
|
+
'wsen:MaxTime': _params.maxTime || 'PT10S',
|
|
46
|
+
'wsen:MaxElements': _params.maxElements || 20
|
|
47
|
+
}]
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function constructReleaseEnumerationRequest(_params) {
|
|
54
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
55
|
+
'resource_uri': _params.resourceUri || 'http://schemas.dmtf.org/wbem/wscim/1/*',
|
|
56
|
+
'action': 'http://schemas.xmlsoap.org/ws/2004/09/enumeration/Release',
|
|
57
|
+
'operationTimeout': _params.operationTimeout
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
res['s:Body'] = {
|
|
61
|
+
'wsen:Release': [{
|
|
62
|
+
'wsen:EnumerationContext': _params.enumerationId
|
|
63
|
+
}]
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function unwrapPropertyValue(value, keepString) {
|
|
70
|
+
if (value && value['Datetime']) {
|
|
71
|
+
value = value['Datetime'][0];
|
|
72
|
+
}
|
|
73
|
+
if (value && value['$'] && value['$']['xsi:nil'] === 'true') {
|
|
74
|
+
value = null;
|
|
75
|
+
}
|
|
76
|
+
// keepString skips the numeric coercion for values that are strings by
|
|
77
|
+
// definition, where coercion mangles hex ("0xC000006D" -> 3221225581) and
|
|
78
|
+
// leading-zero values.
|
|
79
|
+
if (!keepString && typeof value === 'string' && !isNaN(value)) {
|
|
80
|
+
value = Number(value);
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getObjects(items, arrayProperties) {
|
|
86
|
+
// NOTE only suitable for objects structures like WMI, need additional handlers for other data types
|
|
87
|
+
if (!items) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
let arrayProps = new Set(arrayProperties || []);
|
|
91
|
+
let itemCollection = Object.values(items[0])[0];
|
|
92
|
+
let itemObjects = [];
|
|
93
|
+
for (let item of itemCollection) {
|
|
94
|
+
let itemObject = {};
|
|
95
|
+
for (let prop in item) {
|
|
96
|
+
if (prop === '$') { continue; }
|
|
97
|
+
let keyName = prop.replace(/^p:/, '');
|
|
98
|
+
let values = item[prop];
|
|
99
|
+
let value;
|
|
100
|
+
if (arrayProps.has(keyName)) {
|
|
101
|
+
// Caller-declared array property (e.g. Win32_NTLogEvent
|
|
102
|
+
// InsertionStrings): ALWAYS an array of raw strings, regardless
|
|
103
|
+
// of element count — the XML alone cannot distinguish a
|
|
104
|
+
// one-element array from a scalar, and string values must not
|
|
105
|
+
// be numerically coerced (hex/leading zeros).
|
|
106
|
+
value = values.map(v => unwrapPropertyValue(v, true));
|
|
107
|
+
} else if (values.length > 1) {
|
|
108
|
+
// Repeated XML elements are how WS-Man encodes multi-valued WMI
|
|
109
|
+
// properties — keep all values instead of only the first.
|
|
110
|
+
value = values.map(v => unwrapPropertyValue(v));
|
|
111
|
+
} else {
|
|
112
|
+
value = unwrapPropertyValue(values[0]);
|
|
113
|
+
}
|
|
114
|
+
itemObject[keyName] = value;
|
|
115
|
+
}
|
|
116
|
+
itemObjects.push(itemObject);
|
|
117
|
+
}
|
|
118
|
+
return itemObjects;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports.doBeginEnumeration = async function (_params) {
|
|
122
|
+
var req = constructBeginEnumerationRequest(_params);
|
|
123
|
+
|
|
124
|
+
var auth = _params.auth;
|
|
125
|
+
if (_params.authOnce) {
|
|
126
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
127
|
+
_params.auth = undefined;
|
|
128
|
+
_params.authOnce = undefined;
|
|
129
|
+
}
|
|
130
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
131
|
+
|
|
132
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
133
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
134
|
+
} else {
|
|
135
|
+
var enumerationId = result['s:Envelope']['s:Body'][0]['n:EnumerateResponse'][0]['n:EnumerationContext'][0];
|
|
136
|
+
_params.enumerationId = enumerationId;
|
|
137
|
+
|
|
138
|
+
if (result['s:Envelope']['s:Body'][0]['n:EnumerateResponse'][0]['n:EndOfSequence']) {
|
|
139
|
+
_params.endOfSequence = true;
|
|
140
|
+
} else {
|
|
141
|
+
_params.endOfSequence = false;
|
|
142
|
+
}
|
|
143
|
+
let items = result['s:Envelope']['s:Body'][0]['n:EnumerateResponse'][0]['w:Items'];
|
|
144
|
+
return getObjects(items, _params.arrayProperties);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
module.exports.doPullEnumeration = async function (_params) {
|
|
149
|
+
var req = constructPullEnumerationRequest(_params);
|
|
150
|
+
|
|
151
|
+
var auth = _params.auth;
|
|
152
|
+
if (_params.authOnce) {
|
|
153
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
154
|
+
_params.auth = undefined;
|
|
155
|
+
_params.authOnce = undefined;
|
|
156
|
+
}
|
|
157
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
158
|
+
|
|
159
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
160
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
161
|
+
} else {
|
|
162
|
+
if (result['s:Envelope']['s:Body'][0]['n:PullResponse'][0]['n:EndOfSequence']) {
|
|
163
|
+
_params.endOfSequence = true;
|
|
164
|
+
} else {
|
|
165
|
+
_params.endOfSequence = false;
|
|
166
|
+
_params.enumerationId = result['s:Envelope']['s:Body'][0]['n:PullResponse'][0]['n:EnumerationContext'][0];
|
|
167
|
+
}
|
|
168
|
+
let items = result['s:Envelope']['s:Body'][0]['n:PullResponse'][0]['n:Items'];
|
|
169
|
+
return getObjects(items, _params.arrayProperties);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
module.exports.doReleaseEnumeration = async function (_params) {
|
|
174
|
+
var req = constructReleaseEnumerationRequest(_params);
|
|
175
|
+
|
|
176
|
+
var auth = _params.auth;
|
|
177
|
+
if (_params.authOnce) {
|
|
178
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
179
|
+
_params.auth = undefined;
|
|
180
|
+
_params.authOnce = undefined;
|
|
181
|
+
}
|
|
182
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
183
|
+
|
|
184
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
185
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
186
|
+
} else {
|
|
187
|
+
return 'success';
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
module.exports.doEnumerateAll = async function (_params) {
|
|
192
|
+
_params.endOfSequence = false;
|
|
193
|
+
var items = [];
|
|
194
|
+
|
|
195
|
+
var result = await module.exports.doBeginEnumeration(_params);
|
|
196
|
+
if (Array.isArray(result)) {
|
|
197
|
+
items.push(...result);
|
|
198
|
+
} else {
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
while (!_params.endOfSequence && _params.enumerationId) {
|
|
203
|
+
var pullResult = await module.exports.doPullEnumeration(_params);
|
|
204
|
+
if (Array.isArray(pullResult)) {
|
|
205
|
+
items.push(...pullResult);
|
|
206
|
+
} else {
|
|
207
|
+
// TODO attempt to release enumeration on error?
|
|
208
|
+
// TODO should we return partial successful items?
|
|
209
|
+
return pullResult;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return items;
|
|
213
|
+
};
|
package/src/http.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const https = require('https');
|
|
3
|
+
const xml2jsparser = require('xml2js').parseString;
|
|
4
|
+
|
|
5
|
+
const DEFAULT_TIMEOUT = 2 * 60 * 1000;
|
|
6
|
+
|
|
7
|
+
module.exports.sendHttp = async function (_data, _host, _port, _path, _auth, _agent, _requestOptions) {
|
|
8
|
+
var xmlRequest = _data;
|
|
9
|
+
var options = {
|
|
10
|
+
agent: _agent,
|
|
11
|
+
host: _host,
|
|
12
|
+
port: _port,
|
|
13
|
+
path: _path,
|
|
14
|
+
method: 'POST',
|
|
15
|
+
timeout: DEFAULT_TIMEOUT
|
|
16
|
+
};
|
|
17
|
+
let headers = {
|
|
18
|
+
'Authorization': _auth,
|
|
19
|
+
'Content-Type': 'application/soap+xml;charset=UTF-8',
|
|
20
|
+
'User-Agent': 'NodeJS WinRM Client',
|
|
21
|
+
'Content-Length': Buffer.byteLength(xmlRequest)
|
|
22
|
+
};
|
|
23
|
+
if (!_auth) {
|
|
24
|
+
delete headers.Authorization;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// merge request options and headers
|
|
28
|
+
if (_requestOptions) {
|
|
29
|
+
Object.assign(options, _requestOptions);
|
|
30
|
+
headers = Object.assign(headers, _requestOptions.headers);
|
|
31
|
+
}
|
|
32
|
+
options.headers = headers;
|
|
33
|
+
|
|
34
|
+
let requestFn = options && options.protocol === 'https:' ? https.request : http.request;
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
var req = requestFn(options, (res) => {
|
|
37
|
+
if (res.statusCode < 200 || res.statusCode > 299 && res.statusCode != 500) {
|
|
38
|
+
reject(new Error('Failed to process the request, status Code: ' + res.statusCode));
|
|
39
|
+
}
|
|
40
|
+
res.setEncoding('utf8');
|
|
41
|
+
var dataBuffer = '';
|
|
42
|
+
res.on('data', (chunk) => {
|
|
43
|
+
dataBuffer += chunk;
|
|
44
|
+
|
|
45
|
+
});
|
|
46
|
+
res.on('end', () => {
|
|
47
|
+
if (!dataBuffer) {
|
|
48
|
+
reject(new Error('Failed to process the request, status Code: ' + res.statusCode));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
xml2jsparser(dataBuffer, (err, result) => {
|
|
52
|
+
if (err) {
|
|
53
|
+
reject(new Error('Data Parsing error', err));
|
|
54
|
+
}
|
|
55
|
+
resolve(result);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (options.timeout > 0) {
|
|
62
|
+
// This is modelled on what the npm request library does with req timeouts
|
|
63
|
+
req.setTimeout(options.timeout, function () {
|
|
64
|
+
if (req) {
|
|
65
|
+
req.abort();
|
|
66
|
+
var e = new Error('ESOCKETTIMEDOUT');
|
|
67
|
+
e.code = 'ESOCKETTIMEDOUT';
|
|
68
|
+
e.connect = false;
|
|
69
|
+
req.emit('error', e);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
req.on('error', (err) => {
|
|
74
|
+
reject(err);
|
|
75
|
+
});
|
|
76
|
+
if (xmlRequest) {
|
|
77
|
+
req.write(xmlRequest);
|
|
78
|
+
}
|
|
79
|
+
req.end();
|
|
80
|
+
|
|
81
|
+
});
|
|
82
|
+
};
|
package/src/invoke.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const js2xmlparser = require('js2xmlparser');
|
|
2
|
+
let winrm_soap_req = require('./base-request.js');
|
|
3
|
+
let winrm_http_req = require('./http.js');
|
|
4
|
+
let util = require('./util.js');
|
|
5
|
+
|
|
6
|
+
function constructInvokeActionRequest(_params) {
|
|
7
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
8
|
+
'resource_uri': _params.resourceUri,
|
|
9
|
+
'action': _params.actionUri || (util.removeQueryString(_params.resourceUri) + '/' + _params.action),
|
|
10
|
+
'selectorSet': _params.selectorSet,
|
|
11
|
+
'operationTimeout': _params.operationTimeout
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
res['s:Body'] = {
|
|
15
|
+
[`p:${_params.action}_INPUT`]: [{
|
|
16
|
+
'@': {
|
|
17
|
+
'xmlns:p': util.removeQueryString(_params.resourceUri)
|
|
18
|
+
},
|
|
19
|
+
'#': _params.actionInput
|
|
20
|
+
}]
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports.doInvokeAction = async function (_params) {
|
|
27
|
+
var req = constructInvokeActionRequest(_params);
|
|
28
|
+
|
|
29
|
+
var auth = _params.auth;
|
|
30
|
+
if (_params.authOnce) {
|
|
31
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
32
|
+
_params.auth = undefined;
|
|
33
|
+
_params.authOnce = undefined;
|
|
34
|
+
}
|
|
35
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
36
|
+
|
|
37
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
38
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
39
|
+
} else {
|
|
40
|
+
return result['s:Envelope']['s:Body'][0][`p:${_params.action}_OUTPUT`][0];
|
|
41
|
+
}
|
|
42
|
+
};
|
package/src/shell.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const js2xmlparser = require('js2xmlparser');
|
|
2
|
+
let winrm_soap_req = require('./base-request.js');
|
|
3
|
+
let winrm_http_req = require('./http.js');
|
|
4
|
+
let util = require('./util.js');
|
|
5
|
+
|
|
6
|
+
function constructCreateShellRequest(_params) {
|
|
7
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
8
|
+
'action': 'http://schemas.xmlsoap.org/ws/2004/09/transfer/Create',
|
|
9
|
+
'operationTimeout': _params.operationTimeout
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
res['s:Header']['wsman:OptionSet'] = [];
|
|
13
|
+
res['s:Header']['wsman:OptionSet'].push({
|
|
14
|
+
'wsman:Option': [{
|
|
15
|
+
'@': {
|
|
16
|
+
'Name': 'WINRS_NOPROFILE'
|
|
17
|
+
},
|
|
18
|
+
'#': 'FALSE'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
'@': {
|
|
22
|
+
'Name': 'WINRS_CODEPAGE'
|
|
23
|
+
},
|
|
24
|
+
'#': '437'
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
});
|
|
28
|
+
res['s:Body'] = {
|
|
29
|
+
'rsp:Shell': [{
|
|
30
|
+
'rsp:InputStreams': 'stdin',
|
|
31
|
+
'rsp:OutputStreams': 'stderr stdout'
|
|
32
|
+
}]
|
|
33
|
+
};
|
|
34
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function constructDeleteShellRequest(_params) {
|
|
39
|
+
var res = winrm_soap_req.getSoapHeaderRequest({
|
|
40
|
+
'resource_uri': 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd',
|
|
41
|
+
'action': 'http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete',
|
|
42
|
+
'shellId': _params.shellId,
|
|
43
|
+
'operationTimeout': _params.operationTimeout
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
res['s:Body'] = {};
|
|
47
|
+
return js2xmlparser.parse('s:Envelope', res);
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports.doCreateShell = async function (_params) {
|
|
52
|
+
var req = constructCreateShellRequest(_params);
|
|
53
|
+
|
|
54
|
+
var auth = _params.auth;
|
|
55
|
+
if (_params.authOnce) {
|
|
56
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
57
|
+
_params.auth = undefined;
|
|
58
|
+
_params.authOnce = undefined;
|
|
59
|
+
}
|
|
60
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
61
|
+
|
|
62
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
63
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
64
|
+
} else {
|
|
65
|
+
var shellId = result['s:Envelope']['s:Body'][0]['rsp:Shell'][0]['rsp:ShellId'][0];
|
|
66
|
+
return shellId;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
module.exports.doDeleteShell = async function (_params) {
|
|
71
|
+
var req = constructDeleteShellRequest(_params);
|
|
72
|
+
|
|
73
|
+
var auth = _params.auth;
|
|
74
|
+
if (_params.authOnce) {
|
|
75
|
+
auth = typeof _params.authOnce === 'string' ? _params.authOnce : _params.auth;
|
|
76
|
+
_params.auth = undefined;
|
|
77
|
+
_params.authOnce = undefined;
|
|
78
|
+
}
|
|
79
|
+
var result = await winrm_http_req.sendHttp(req, _params.host, _params.port, _params.path, auth, _params.agent, _params.requestOptions);
|
|
80
|
+
|
|
81
|
+
if (result['s:Envelope']['s:Body'][0]['s:Fault']) {
|
|
82
|
+
return new Error(util.faultFormatter(result['s:Envelope']['s:Body'][0]['s:Fault']));
|
|
83
|
+
} else {
|
|
84
|
+
//var output = result['s:Envelope']['s:Body'][0]['rsp:ReceiveResponse'][0]['rsp:Stream'];
|
|
85
|
+
return 'success';
|
|
86
|
+
}
|
|
87
|
+
};
|
package/src/util.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module.exports.faultFormatter = function (faultElement) {
|
|
2
|
+
let faultCode = 'Unknown Fault';
|
|
3
|
+
let faultReason = '';
|
|
4
|
+
|
|
5
|
+
if (faultElement[0]['s:Code'] && faultElement[0]['s:Code'][0]['s:Subcode'] && faultElement[0]['s:Code'][0]['s:Subcode'][0]['s:Value']) {
|
|
6
|
+
faultCode = faultElement[0]['s:Code'][0]['s:Subcode'][0]['s:Value'];
|
|
7
|
+
}
|
|
8
|
+
if (faultElement[0]['s:Reason'] && faultElement[0]['s:Reason'][0]['s:Text'] && faultElement[0]['s:Reason'][0]['s:Text'][0]['_']) {
|
|
9
|
+
faultReason = faultElement[0]['s:Reason'][0]['s:Text'][0]['_'];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (faultReason) {
|
|
13
|
+
return `${faultCode}: ${faultReason}`;
|
|
14
|
+
}
|
|
15
|
+
return `${faultCode}`;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports.removeQueryString = function (uri) {
|
|
19
|
+
return uri && uri.replace(/\?.*$/, '');
|
|
20
|
+
};
|
package/test/test.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var winrm = require('../index.js');
|
|
2
|
+
|
|
3
|
+
async function performTest() {
|
|
4
|
+
try {
|
|
5
|
+
//var result = await winrm.runCommand('mkdir D:\\winrmtest001', '10.xxx.xxx.xxx', 5985, 'username', 'password');
|
|
6
|
+
var result = await winrm.runCommand('ipconfig /all', '10.xxx.xxx.xxx', 'username', 'password', 5985);
|
|
7
|
+
console.log(result);
|
|
8
|
+
} catch (error) {
|
|
9
|
+
console.error(`Exception Occurred: ${error}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
performTest();
|