2

我在 NodeJS 中遇到了 Windows 程序 WMIC.exe(用于查询 Windows Management Instrumentation)的问题。

我可以生成一个 wmic.exe 进程,但它不会输出任何内容或接受任何输入。但是,如果我将标准输入设置为 null,它将正确运行并且我会收到输出。

var spawn = require('child_process').spawn;
var wmic = spawn('wmic', [], {stdio: ['ignore']});

wmic.stdout.on('data', function(data) {
  console.log('Data received:' + data);
});

wmic.on('close', function(code) {
  console.log('Spawned process ended with code: ' + code);
});

我想以交互方式使用它支持的 wmic.exe,使其保持打开状态,这样我就不必为每个 WMI 查询重复启动它。其他人在使用 wmic.exe 时也遇到过类似的问题,但他们只想捕获单个查询的输出,因此拥有空标准输入对他们来说并不重要。

更新

如果我执行以下操作...

var spawn = require('child_process').spawn;
var wmic = spawn('wmic', []);

wmic.stdout.on('data', function(data) {
  console.log('Data received:' + data);
});

wmic.stderr.on('data', function(data) {
  console.log('Error! - ' + data);
});

wmic.on('close', function(code) {
  console.log('Spawned process ended with code: ' + code);
});

wmic.stdin.end('cpu get caption /format:csv\n');

然后它实际上会响应一个结果,提示为下一个查询做好准备,但接下来会结束该过程,显然我不能在 .end() 之后使用 .write()。相反,将其更改为 .write(),进程根本没有响应,我什至没有从使用 .end() 时收到的 stdout "wmic:root\cli>" 得到提示。

或者

wmic.stdin.push(null);
wmic.stdin.write('cpu/n'); // Ctrl-Z aka Windows EOF control code

如果我使用上面的方法,而不是 .end() 调用,它也可以工作。但似乎如果我不继续向它抛出常量数据,该过程就会结束。

甚至

wmic.stdin.write('cpu');
wmic.stdin.write('\x1a');

这也有效,但是 wmic.exe 进程再次决定在返回 cpu 结果后退出。:/

几乎

var wmic = spawn('wmic.exe', [], {stdio: [process.stdin, 'pipe', 'pipe']});

这行得通。该过程正确启动,因此我通过 wmic.stdout.on('data', fn) 收到来自 wmic.exe 的提示,并且它保持打开状态。但是,我无法通过代码向它发送输入,但可以直接在命令提示符窗口中输入。我输入的任何内容都会通过节点脚本正确执行和输出。再一次,奇怪的是它与这个管道一起工作,但不是我设置的,对我来说没用,因为我想通过代码发送命令,而不是输入它们。

4

3 回答 3

3

您希望以wmic交互方式使用,但由来自应用程序的输入驱动,而不是在控制台键入的输入。

对于任何应用程序来说,实现这一点的正常方法是从管道输入。方便的是,如果您不指定任何其他stdio选项,NodeJS 似乎默认创建管道。

问题是wmic当它从管道接收输入时表现不佳。在输入完成之前它拒绝做任何事情;然后它会处理所有输入并停止查找。 wmic当管道关闭或收到 CTRL-Z 时,认为输入完成。

因此,您不能发出一个命令,读取输出然后发出另一个命令。 wmic直到它认为它已收到所有命令时才写入输出,然后它将不再接受。

您可以在控制台上说明这个问题。 type con: | wmic通过管道输入键盘输入,因此wmic进入其损坏模式。在下面的示例中,这后面是几个命令。请注意,在输入wmic之前什么都不做CTRL-Z

C:\>type con: | wmic
cpu get name
useraccount list brief
^Z
wmic:root\cli>cpu get name
Name
Pentium(R) Dual-Core CPU       T4500  @ 2.30GHz

wmic:root\cli>
"/?" for help, QUIT to Exit.
wmic:root\cli>useraccount list brief
AccountType  Caption                    Domain     FullName         Name
512          frog\Administrator         frog                        Administrator

wmic:root\cli>
"/?" for help, QUIT to Exit.
wmic:root\cli>
C:\>

您可能会认为(看这个例子)wmic只有一个大的输出缓冲区。但是,如果您打开跟踪(/TRACE:ON作为第一个命令)wmic会产生大量输出,但在输入完成之前什么都不会。

一个解决方案是不重定向标准输入,就像你的最后一个例子一样,所以输入来自键盘。(注意,当 Windows 控制台应用程序从键盘接收输入时,它不是通过管道输入的。因此,您的最后一个示例没有使用管道,这就是行为不同的原因。)

然后,您可以wmic通过模拟击键来提供输入。 这个问题的答案建议了几种方法:使用SendKeys或发送WM_KEYUP消息。这不是一个很好的解决方案。

于 2013-09-03T22:51:14.343 回答
2

为后人...

现在可以通过使用ms-wmic包来实现:

这完全绕过了必须直接与 CLI 交互,并允许您WMIC通过预设 API 进行处理。


但是您在上面的示例中尝试使用的特定WMIC内容也由windows-cpu包处理:

于 2015-12-08T18:59:38.227 回答
0

这就是它对我的工作方式:

var spawn = require('child_process').spawn;
var wmic = spawn('wmic', []);

wmic.stdout.on('data', function(data) {
  console.log('Data received: [[' + data + ']]');
});

wmic.stderr.on('data', function(data) {
  console.log('Error! - ' + data);
});

wmic.on('close', function(code) {
  console.log('Spawned process ended with code: ' + code);
});

wmic.stdin.end( 'cpu get caption /format:csv' );
于 2014-09-08T23:40:47.030 回答