允许 powershell 控制台在 NodeJS 中显示

Allow powershell console to show in NodeJS

我有一个 NodeJS (Electron) 客户端,它运行正在执行以下代码:

child = spawn("powershell.exe",['-ExecutionPolicy', 'ByPass', '-File', require("path").resolve(__dirname, '../../../../updater.ps1')]);
child.on("exit",function(){
    require('electron').remote.getCurrentWindow().close();
});

这打开的文件是一个 powershell 文件,它下载并解压缩更新。如果我手动 运行 这个文件,我会得到 powershell 控制台,它会显示一个下载和解包的进度条。但是,运行从上面的代码中调用它不会显示控制台。

如何让我的代码在 运行 期间显示 powershell 控制台?我很难制定搜索词来找到答案。

我尝试过的事情:

我也试过切换到 exec

exec('powershell -ExecutionPolicy Bypass -File ' + updater_path, function callback(error, stdout, stderr){
    console.log(error);
});

哪个 运行 是文件,但仍然没有显示控制台。

答案最好允许我 运行 未附加到 NodeJS 客户端的 powershell 文件,并且还会在 运行ning 时显示 powershell 控制台。

这是我当前的代码:

updater = spawn("powershell.exe",['-ExecutionPolicy', 'ByPass', '-File', remote.app.getAppPath() + '\app\files\scripts\' + data.type + '_updater.ps1'], { detached: true, stdio: 'ignore' });
updater.unref();

实际上什么都不做,甚至看起来根本不像 运行脚本。

我使用批处理文件尝试过相同的操作,但从未打开过。

updater = spawn("cmd",[remote.app.getAppPath() + '\app\files\scripts\launch_updater.bat'], { detached: true, stdio: ['ignore', 'ignore', 'ignore'] });
updater.unref();

我怀疑您需要传递 shell 选项来告诉 node 在哪个 shell 上执行命令。这默认为 Windows 上的 process.env.ComSpec,如果出于某种原因未设置,则默认为 cmd.exe

参考:https://nodejs.org/api/child_process.html#child_process_default_windows_shell

Although Microsoft specifies %COMSPEC% must contain the path to 'cmd.exe' in the root environment, child processes are not always subject to the same requirement. Thus, in child_process functions where a shell can be spawned, 'cmd.exe' is used as a fallback if process.env.ComSpec is unavailable.

PowerShell shell 支持已通过 this commit 提供。

由于 exec 命令有效,我建议从这里开始并尝试让 window 显示。尝试在选项对象中传递 shell: 'PowerShell'。对于 child_process.execwindowsHide 默认为 false,但传递它也可能无害:

exec('powershell -ExecutionPolicy Bypass -File ' + updater_path, { shell: 'PowerShell', windowsHide: false }, function callback(error, stdout, stderr){
    console.log(error);
});  

您也可以通过类似的选项使其与 spawn 一起使用:{ shell: 'PowerShell', windowsHide: false }

我最终通过使用 exec 调用一个批处理文件来解决这个问题,这个批处理文件运行 powershell 文件。

//call buffer .bat file, close main window after 3 seconds to make sure it runs before closing.
exec('start ' +  remote.app.getAppPath() + '\app\files\scripts\launch_updater.bat ' + data.type);
setTimeout(function() {
    require('electron').remote.getCurrentWindow().close();
}, 3000);

launch_updater.bat:

@ECHO OFF
set arg1=%~1
start powershell.exe -executionpolicy bypass -File "%~dp0/%arg1%_updater.ps1"
for /f "skip=3 tokens=2 delims= " %%a in ('tasklist /fi "imagename eq cmd.exe"') do (
    if "%%a" neq "%current_pid%" (
        TASKKILL /PID %%a /f >nul 2>nul
    )
)
exit /b

批处理文件中的循环本质上只是为了在不打开命令 window 的情况下自行关闭。我根据它是哪种更新来传递参数。

shell:truedetached:true 足以打开 PowerShell。

我已经为独立的 PowerShell window:

制作了这个简单的 demo
  • 根:
    • index.js(也就是您的主要 js 文件)
    • powerShell.js(分离的 powershell window)
    • showTime.ps1(又名您的文件)

powerShell.js 中会发现我将保持 PS Window 在 defaultPowerShellArguments 变量下打开的参数分开。

Advice: I see alot of powershell at the spawn command parameter, i cannot stress this enough, add the .exe extension too when running under Windows, correct ispowershell.exe. If you happen to use just powershell and nodepad will all of a sudden pop-up echoing your script, you will have a hard time trying to figure it out.

index.js

const powerShell = require('./powerShell');

let seconds = 5;
let remaining = seconds;
let nd = new Date().getTime() + (seconds * 1000);

setInterval(() => {
    remaining -= 1
    let time = new Date();
    console.log('Your code running at:', time.toTimeString());

    if (remaining === 3) {
        console.log('Opening powershell...')
        powerShell([
            "-File",
            "./showTime.ps1"
        ]);
    }

    if (time.getTime() > nd) {
        console.log('Main script will exit.');
        process.exit(0);
    }
}, 1000);

powerShell.js

module.exports = (spawnArguments) => {
    if (typeof spawnArguments === "undefined" || !(spawnArguments instanceof Array)) {
        spawnArguments = [];
    }
    const {spawn} = require('child_process');
    let defaultPowerShellArguments = ["-ExecutionPolicy", "Bypass", "-NoExit",];
    let powershell = spawn('powershell.exe', [...defaultPowerShellArguments, ...spawnArguments], {
        shell: true,
        detached: true,
        // You can tell PowerShell to open straight to the file directory
        // Then you can use the relative path of your file.
        // cwd: 'ABSOLUTE_PATH_TO_A_VALID_FOLDER'
        // cwd: 'C:/'
    });
}

showTime.ps1

Get-Date -Format G