replace av and chassistype with wmi instead of powershell
Signed-off-by: si458 <simonsmith5521@gmail.com>
si458 committed
Nov 16, 2025 at 16:18 UTC
9545bec218b31555e2814d4d2775cdac7a64ca1f
3 files changed
+477
-54
agents/modules_meshcore/computer-identifiers.js
+5
-10
@@ -702,17 +702,12 @@ function hexToAscii(hexString) {
702
703
function win_chassisType()
704
{
705
- // needs to be replaced with win-wmi but due to bug in win-wmi it doesnt handle arrays correctly
706
- var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
707
- if (child == null) { return ([]); }
708
- child.descriptorMetadata = 'process-manager';
709
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
710
- child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
711
- child.stdin.write('Get-WmiObject Win32_SystemEnclosure | Select-Object -ExpandProperty ChassisTypes\r\n');
712
- child.stdin.write('exit\r\n');
713
- child.waitExit();
705
+ // use new win-wmi-fixed module to get arrays correctly for time being
706
try {
715
- return (parseInt(child.stdout.str));
707
+ var tokens = require('win-wmi-fixed').query('ROOT\\CIMV2', 'SELECT ChassisTypes FROM Win32_SystemEnclosure', ['ChassisTypes']);
708
+ if (tokens[0]) {
709
+ return (parseInt(tokens[0]['ChassisTypes'][0]));
710
+ }
711
} catch (e) {
712
return (2); // unknown
713
}
agents/modules_meshcore/win-info.js
+39
-44
@@ -36,53 +36,48 @@ function qfe()
36
}
37
function av()
38
{
39
- var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
40
- if (child == null) { return ([]); }
41
-
42
- child.descriptorMetadata = 'process-manager';
43
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
44
- child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
45
-
46
- child.stdin.write('[reflection.Assembly]::LoadWithPartialName("system.core")\r\n');
47
- child.stdin.write('Get-WmiObject -Namespace "root/SecurityCenter2" -Class AntiVirusProduct | ');
48
- child.stdin.write('ForEach-Object -Process { ');
49
- child.stdin.write('$matches = [regex]::Matches($_.pathToSignedProductExe, "%(.*?)%"); ');
50
- child.stdin.write('$modifiedPath = $_.pathToSignedProductExe; ');
51
- child.stdin.write('foreach ($match in $matches) { ');
52
- child.stdin.write('$modifiedPath = $modifiedPath -replace [regex]::Escape($match.Value), [System.Environment]::GetEnvironmentVariable($match.Groups[1].Value, "Process") ');
53
- child.stdin.write('} ');
54
- child.stdin.write('$flag = $true; ');
55
- child.stdin.write('if ($modifiedPath -ne "windowsdefender://"){ ');
56
- child.stdin.write('if (-not (Test-Path -Path $modifiedPath -PathType Leaf)) { ');
57
- child.stdin.write('$flag = $false; ');
58
- child.stdin.write('} ');
59
- child.stdin.write('} ');
60
- child.stdin.write('if ($flag -eq $true) { ')
61
- child.stdin.write('$Bytes = [System.Text.Encoding]::UTF8.GetBytes($_.displayName); ');
62
- child.stdin.write('$EncodedText =[Convert]::ToBase64String($Bytes); ');
63
- child.stdin.write('Write-Output ("{0},{1}" -f $_.productState,$EncodedText); ');
64
- child.stdin.write('} ');
65
- child.stdin.write('}\r\n ');
66
- child.stdin.write('exit\r\n');
67
- child.waitExit();
68
-
69
- if (child.stdout.str == '') { return ([]); }
70
-
71
- var lines = child.stdout.str.trim().split('\r\n');
39
var result = [];
73
- for (i = 0; i < lines.length; ++i)
74
- {
75
- var keys = lines[i].split(',');
76
- if(keys.length == 2)
77
- {
78
- var status = {};
79
- status.product = Buffer.from(keys[1], 'base64').toString();
80
- status.updated = (parseInt(keys[0]) & 0x10) == 0;
81
- status.enabled = (parseInt(keys[0]) & 0x1000) == 0x1000;
82
- result.push(status);
40
+ try {
41
+ var tokens = require('win-wmi').query('ROOT\\SecurityCenter2', 'SELECT * FROM AntiVirusProduct');
42
+ if (tokens.length == 0) { return ([]); }
43
+ // Process each antivirus product
44
+ for (var i = 0; i < tokens.length; ++i) {
45
+ var product = tokens[i];
46
+ var modifiedPath = product.pathToSignedProductExe || '';
47
+ // Expand environment variables (e.g., %ProgramFiles%)
48
+ var regex = /%([^%]+)%/g;
49
+ var match;
50
+ while ((match = regex.exec(product.pathToSignedProductExe)) !== null) {
51
+ var envVar = match[1];
52
+ var envValue = process.env[envVar] || '';
53
+ if (envValue) {
54
+ modifiedPath = modifiedPath.replace(match[0], envValue);
55
+ }
56
+ }
57
+ // Check if the executable exists (unless it's Windows Defender pseudo-path)
58
+ var flag = true;
59
+ if (modifiedPath !== 'windowsdefender://') {
60
+ try {
61
+ if (!require('fs').existsSync(modifiedPath)) {
62
+ flag = false;
63
+ }
64
+ } catch (ex) {
65
+ flag = false;
66
+ }
67
+ }
68
+ // Only include products with valid executables
69
+ if (flag) {
70
+ var status = {};
71
+ status.product = product.displayName || '';
72
+ status.updated = (parseInt(product.productState) & 0x10) == 0;
73
+ status.enabled = (parseInt(product.productState) & 0x1000) == 0x1000;
74
+ result.push(status);
75
+ }
76
}
77
+ return (result);
78
+ } catch (ex) {
79
+ return ([]);
80
}
85
- return (result);
81
}
82
function defrag(options)
83
{
agents/modules_meshcore/win-wmi-fixed.js
new
+433
@@ -0,0 +1,433 @@
1
+/*
2
+Copyright 2021 Intel Corporation
3
+
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
+
17
+var promise = require('promise');
18
+var GM = require('_GenericMarshal');
19
+const CLSID_WbemAdministrativeLocator = '{CB8555CC-9128-11D1-AD9B-00C04FD8FDFF}';
20
+const IID_WbemLocator = '{dc12a687-737f-11cf-884d-00aa004b2e24}';
21
+const WBEM_FLAG_BIDIRECTIONAL = 0;
22
+const WBEM_INFINITE = -1;
23
+const WBEM_FLAG_ALWAYS = 0;
24
+const E_NOINTERFACE = 0x80004002;
25
+var OleAut32 = GM.CreateNativeProxy('OleAut32.dll');
26
+OleAut32.CreateMethod('SafeArrayAccessData');
27
+
28
+var wmi_handlers = {};
29
+
30
+const LocatorFunctions = ['QueryInterface', 'AddRef', 'Release', 'ConnectToServer'];
31
+
32
+//
33
+// Reference for IWbemServices can be found at:
34
+// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemservices
35
+//
36
+const ServiceFunctions = [
37
+ 'QueryInterface',
38
+ 'AddRef',
39
+ 'Release',
40
+ 'OpenNamespace',
41
+ 'CancelAsyncCall',
42
+ 'QueryObjectSink',
43
+ 'GetObject',
44
+ 'GetObjectAsync',
45
+ 'PutClass',
46
+ 'PutClassAsync',
47
+ 'DeleteClass',
48
+ 'DeleteClassAsync',
49
+ 'CreateClassEnum',
50
+ 'CreateClassEnumAsync',
51
+ 'PutInstance',
52
+ 'PutInstanceAsync',
53
+ 'DeleteInstance',
54
+ 'DeleteInstanceAsync',
55
+ 'CreateInstanceEnum',
56
+ 'CreateInstanceEnumAsync',
57
+ 'ExecQuery',
58
+ 'ExecQueryAsync',
59
+ 'ExecNotificationQuery',
60
+ 'ExecNotificationQueryAsync',
61
+ 'ExecMethod',
62
+ 'ExecMethodAsync'
63
+];
64
+
65
+//
66
+// Reference to IEnumWbemClassObject can be found at:
67
+// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-ienumwbemclassobject
68
+//
69
+const ResultsFunctions = [
70
+ 'QueryInterface',
71
+ 'AddRef',
72
+ 'Release',
73
+ 'Reset',
74
+ 'Next',
75
+ 'NextAsync',
76
+ 'Clone',
77
+ 'Skip'
78
+];
79
+
80
+//
81
+// Reference to IWbemClassObject can be found at:
82
+// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemclassobject
83
+//
84
+const ResultFunctions = [
85
+ 'QueryInterface',
86
+ 'AddRef',
87
+ 'Release',
88
+ 'GetQualifierSet',
89
+ 'Get',
90
+ 'Put',
91
+ 'Delete',
92
+ 'GetNames',
93
+ 'BeginEnumeration',
94
+ 'Next',
95
+ 'EndEnumeration',
96
+ 'GetPropertyQualifierSet',
97
+ 'Clone',
98
+ 'GetObjectText',
99
+ 'SpawnDerivedClass',
100
+ 'SpawnInstance',
101
+ 'CompareTo',
102
+ 'GetPropertyOrigin',
103
+ 'InheritsFrom',
104
+ 'GetMethod',
105
+ 'PutMethod',
106
+ 'DeleteMethod',
107
+ 'BeginMethodEnumeration',
108
+ 'NextMethod',
109
+ 'EndMethodEnumeration',
110
+ 'GetMethodQualifierSet',
111
+ 'GetMethodOrigin'
112
+];
113
+
114
+//
115
+// Reference to IWbemObjectSink can be found at:
116
+// https://learn.microsoft.com/en-us/windows/win32/wmisdk/iwbemobjectsink
117
+//
118
+const QueryAsyncHandler =
119
+ [
120
+ {
121
+ cx: 10, parms: 3, name: 'QueryInterface', func: function (j, riid, ppv)
122
+ {
123
+ var ret = GM.CreateVariable(4);
124
+ console.info1('QueryInterface', riid.Deref(0, 16).toBuffer().toString('hex'));
125
+ switch (riid.Deref(0, 16).toBuffer().toString('hex'))
126
+ {
127
+ case '0000000000000000C000000000000046': // IID_IUnknown
128
+ j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
129
+ ret.increment(0, true);
130
+ //++this.p.refcount;
131
+ console.info1('QueryInterface (IID_IUnknown)', this.refcount);
132
+ break;
133
+ case '0178857C8173CF11884D00AA004B2E24': // IID_IWmiObjectSink
134
+ j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
135
+ ret.increment(0, true);
136
+ //++this.p.refcount;
137
+ console.info1('QueryInterface (IID_IWmiObjectSink)', this.refcount);
138
+ break;
139
+ default:
140
+ ret.increment(E_NOINTERFACE, true);
141
+ console.info1(riid.Deref(0, 16).toBuffer().toString('hex'), 'returning E_NOINTERFACE');
142
+ break;
143
+ }
144
+
145
+ return (ret);
146
+ }
147
+ },
148
+ {
149
+ cx: 11, parms: 1, name: 'AddRef', func: function ()
150
+ {
151
+ ++this.refcount;
152
+ console.info1('AddRef', this.refcount);
153
+ return (GM.CreateVariable(4));
154
+ }
155
+ },
156
+ {
157
+ cx: 12, parms: 1, name: 'Release', func: function ()
158
+ {
159
+ --this.refcount;
160
+ console.info1('Release', this.refcount);
161
+ if (this.refcount == 0)
162
+ {
163
+ console.info1('No More References');
164
+
165
+ this.cleanup();
166
+ this.services.funcs.Release(this.services.Deref());
167
+
168
+ this.services = null;
169
+ this.p = null;
170
+ if (this.callbackDispatched)
171
+ {
172
+ setImmediate(function (j) { j.locator = null; }, this);
173
+ }
174
+ else
175
+ {
176
+ this.locator = null;
177
+ }
178
+
179
+ console.info1('No More References [END]');
180
+ }
181
+ return (GM.CreateVariable(4));
182
+ }
183
+ },
184
+ {
185
+ cx: 13, parms: 3, name: 'Indicate', func: function (j, count, arr)
186
+ {
187
+ console.info1('Indicate', count.Val);
188
+ var j, nme, len, nn;
189
+
190
+ for (var i = 0; i < count.Val; ++i)
191
+ {
192
+ j = arr.Deref((i * GM.PointerSize) + 0, GM.PointerSize);
193
+ this.results.push(enumerateProperties(j, this.fields));
194
+ }
195
+
196
+ var ret = GM.CreateVariable(4);
197
+ ret.increment(0, true);
198
+ return (ret);
199
+ }
200
+ },
201
+ {
202
+ cx: 14, parms: 5, name: 'SetStatus', func: function (j, lFlags, hResult, strParam, pObjParam)
203
+ {
204
+ console.info1('SetStatus', hResult.Val);
205
+
206
+ var ret = GM.CreateVariable(4);
207
+ ret.increment(0, true);
208
+
209
+ if (hResult.Val == 0)
210
+ {
211
+ this.p.resolve(this.results);
212
+ }
213
+ else
214
+ {
215
+ this.p.reject(hResult.Val);
216
+ }
217
+ return (ret);
218
+ }
219
+ }
220
+ ];
221
+
222
+
223
+function enumerateProperties(j, fields)
224
+{
225
+ //
226
+ // Reference to SafeArrayAccessData() can be found at:
227
+ // https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayaccessdata
228
+ //
229
+
230
+ var nme, len, nn;
231
+ var properties = [];
232
+ var values = {};
233
+
234
+ j.funcs = require('win-com').marshalFunctions(j.Deref(), ResultFunctions);
235
+
236
+ // First we need to enumerate the COM Array
237
+ if (fields != null && Array.isArray(fields))
238
+ {
239
+ properties = fields;
240
+ }
241
+ else
242
+ {
243
+ nme = GM.CreatePointer();
244
+ j.funcs.GetNames(j.Deref(), 0, WBEM_FLAG_ALWAYS, 0, nme);
245
+ len = nme.Deref().Deref(GM.PointerSize == 8 ? 24 : 16, 4).toBuffer().readUInt32LE();
246
+ nn = GM.CreatePointer();
247
+ OleAut32.SafeArrayAccessData(nme.Deref(), nn);
248
+
249
+
250
+ for (var i = 0; i < len - 1; ++i)
251
+ {
252
+ properties.push(nn.Deref().increment(i * GM.PointerSize).Deref().Wide2UTF8);
253
+ }
254
+ }
255
+
256
+ // Now we need to introspect the Array Fields
257
+ for (var i = 0; i < properties.length; ++i)
258
+ {
259
+ var tmp1 = GM.CreateVariable(24);
260
+ if (j.funcs.Get(j.Deref(), GM.CreateVariable(properties[i], { wide: true }), 0, tmp1, 0, 0).Val == 0)
261
+ {
262
+ //
263
+ // Reference for IWbemClassObject::Get() can be found at:
264
+ // https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-get
265
+ //
266
+
267
+ var vartype = tmp1.toBuffer().readUInt16LE();
268
+ var isArray = (vartype & 0x2000) != 0; // VT_ARRAY flag
269
+ var baseType = vartype & 0x0FFF;
270
+
271
+ if (isArray)
272
+ {
273
+ // Handle array types (VT_ARRAY | base type)
274
+ var safeArray = tmp1.Deref(8, GM.PointerSize).Deref();
275
+ var arrayLength = safeArray.Deref(GM.PointerSize == 8 ? 24 : 16, 4).toBuffer().readUInt32LE();
276
+ var arrayData = GM.CreatePointer();
277
+ OleAut32.SafeArrayAccessData(safeArray, arrayData);
278
+
279
+ var arrayValues = [];
280
+ for (var k = 0; k < arrayLength; ++k)
281
+ {
282
+ switch (baseType)
283
+ {
284
+ case 0x0002: // VT_I2
285
+ arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE());
286
+ break;
287
+ case 0x0003: // VT_I4
288
+ case 0x0016: // VT_INT
289
+ arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readInt32LE());
290
+ break;
291
+ case 0x000B: // VT_BOOL
292
+ arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE() != 0);
293
+ break;
294
+ case 0x0010: // VT_I1
295
+ arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readInt8());
296
+ break;
297
+ case 0x0011: // VT_UI1
298
+ arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readUInt8());
299
+ break;
300
+ case 0x0012: // VT_UI2
301
+ arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readUInt16LE());
302
+ break;
303
+ case 0x0013: // VT_UI4
304
+ case 0x0017: // VT_UINT
305
+ arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readUInt32LE());
306
+ break;
307
+ case 0x0008: // VT_BSTR
308
+ arrayValues.push(arrayData.Deref().Deref(k * GM.PointerSize, GM.PointerSize).Deref().Wide2UTF8);
309
+ break;
310
+ }
311
+ }
312
+ values[properties[i]] = arrayValues;
313
+ }
314
+ else
315
+ {
316
+ // Handle scalar types
317
+ switch (vartype)
318
+ {
319
+ case 0x0000: // VT_EMPTY
320
+ case 0x0001: // VT_NULL
321
+ values[properties[i]] = null;
322
+ break;
323
+ case 0x0002: // VT_I2
324
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt16LE();
325
+ break;
326
+ case 0x0003: // VT_I4
327
+ case 0x0016: // VT_INT
328
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE();
329
+ break;
330
+ case 0x000B: // VT_BOOL
331
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE() != 0;
332
+ break;
333
+ case 0x000E: // VT_DECIMAL
334
+ break;
335
+ case 0x0010: // VT_I1
336
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt8();
337
+ break;
338
+ case 0x0011: // VT_UI1
339
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt8();
340
+ break;
341
+ case 0x0012: // VT_UI2
342
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt16LE();
343
+ break;
344
+ case 0x0013: // VT_UI4
345
+ case 0x0017: // VT_UINT
346
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt32LE();
347
+ break;
348
+ //case 0x0014: // VT_I8
349
+ // break;
350
+ //case 0x0015: // VT_UI8
351
+ // break;
352
+ case 0x0008: // VT_BSTR
353
+ values[properties[i]] = tmp1.Deref(8, GM.PointerSize).Deref().Wide2UTF8;
354
+ break;
355
+ default:
356
+ console.info1('VARTYPE: ' + vartype);
357
+ break;
358
+ }
359
+ }
360
+ }
361
+ }
362
+
363
+ return (values);
364
+}
365
+
366
+function queryAsync(resourceString, queryString, fields)
367
+{
368
+ var p = new promise(require('promise').defaultInit);
369
+ var resource = GM.CreateVariable(resourceString, { wide: true });
370
+ var language = GM.CreateVariable("WQL", { wide: true });
371
+ var query = GM.CreateVariable(queryString, { wide: true });
372
+ var results = GM.CreatePointer();
373
+
374
+ // Setup the Async COM handler for QueryAsync()
375
+ var handlers = require('win-com').marshalInterface(QueryAsyncHandler);
376
+ handlers.refcount = 1;
377
+ handlers.results = [];
378
+ handlers.fields = fields;
379
+ handlers.locator = require('win-com').createInstance(require('win-com').CLSIDFromString(CLSID_WbemAdministrativeLocator), require('win-com').IID_IUnknown);
380
+ handlers.locator.funcs = require('win-com').marshalFunctions(handlers.locator, LocatorFunctions);
381
+
382
+ handlers.services = require('_GenericMarshal').CreatePointer();
383
+ if (handlers.locator.funcs.ConnectToServer(handlers.locator, resource, 0, 0, 0, 0, 0, 0, handlers.services).Val != 0) { throw ('Error calling ConnectToService'); }
384
+
385
+ handlers.services.funcs = require('win-com').marshalFunctions(handlers.services.Deref(), ServiceFunctions);
386
+ handlers.p = p;
387
+
388
+ // Make the COM call
389
+ if (handlers.services.funcs.ExecQueryAsync(handlers.services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, handlers).Val != 0)
390
+ {
391
+ throw ('Error in Query');
392
+ }
393
+
394
+ // Hold a reference to the callback object
395
+ wmi_handlers[handlers._hashCode()] = handlers;
396
+ return (p);
397
+}
398
+function query(resourceString, queryString, fields)
399
+{
400
+ var resource = GM.CreateVariable(resourceString, { wide: true });
401
+ var language = GM.CreateVariable("WQL", { wide: true });
402
+ var query = GM.CreateVariable(queryString, { wide: true });
403
+ var results = GM.CreatePointer();
404
+
405
+ // Connect the locator connection for WMI
406
+ var locator = require('win-com').createInstance(require('win-com').CLSIDFromString(CLSID_WbemAdministrativeLocator), require('win-com').IID_IUnknown);
407
+ locator.funcs = require('win-com').marshalFunctions(locator, LocatorFunctions);
408
+ var services = require('_GenericMarshal').CreatePointer();
409
+ if (locator.funcs.ConnectToServer(locator, resource, 0, 0, 0, 0, 0, 0, services).Val != 0) { throw ('Error calling ConnectToService'); }
410
+
411
+ // Execute the Query
412
+ services.funcs = require('win-com').marshalFunctions(services.Deref(), ServiceFunctions);
413
+ if (services.funcs.ExecQuery(services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, results).Val != 0) { throw ('Error in Query'); }
414
+
415
+ results.funcs = require('win-com').marshalFunctions(results.Deref(), ResultsFunctions);
416
+ var returnedCount = GM.CreateVariable(8);
417
+ var result = GM.CreatePointer();
418
+ var ret = [];
419
+
420
+ // Enumerate the results
421
+ while (results.funcs.Next(results.Deref(), WBEM_INFINITE, 1, result, returnedCount).Val == 0)
422
+ {
423
+ ret.push(enumerateProperties(result, fields));
424
+ }
425
+
426
+ results.funcs.Release(results.Deref());
427
+ services.funcs.Release(services.Deref());
428
+ locator.funcs.Release(locator);
429
+
430
+ return (ret);
431
+}
432
+
433
+module.exports = { query: query, queryAsync: queryAsync };