@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 ADDED
@@ -0,0 +1,15 @@
1
+ language: node_js
2
+
3
+ node_js:
4
+ - "11"
5
+ - "10"
6
+ - "9"
7
+ - "8"
8
+
9
+ os:
10
+ - linux
11
+ - osx
12
+ - windows
13
+
14
+ after_success:
15
+ - './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls'
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
+ [![npm version](https://badge.fury.io/js/nodejs-winrm.svg)](https://badge.fury.io/js/nodejs-winrm)
4
+ [![Build Status](https://travis-ci.org/shoneslab/nodejs-winrm.svg?branch=master)](https://travis-ci.org/shoneslab/nodejs-winrm)
5
+ [![Build Status](https://dev.azure.com/SHONEJACOB/SHONEJACOB/_apis/build/status/shoneslab.nodejs-winrm?branchName=master)](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'
@@ -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
+ ];
@@ -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
+ };
@@ -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();