如何使用 Nodejs 和 spawn 在 Windows 10 上以管理员身份运行一些 CMD 命令?
Posted
技术标签:
【中文标题】如何使用 Nodejs 和 spawn 在 Windows 10 上以管理员身份运行一些 CMD 命令?【英文标题】:How to run some CMD commands on Windows 10 as administrator using Nodejs and spawn? 【发布时间】:2019-04-05 00:27:56 【问题描述】:我在 Windows 10 上使用 Nodejs。每次打开应用程序时,我都想检查扩展名为 ext
的文件是否与我的应用程序相关联。如果不是,我需要在 cmd 上运行此命令才能再次建立关联:
assoc .ext=CustomExt
ftype CustomExt=app.exe %1 %*
但我需要管理员权限才能完成这项工作。
我已经阅读了this thread,其中 Jeff M 准确地说出了我想要实现的目标,但没有人回答他:
从可用性的角度来看,理想的应该是,只有当用户在我的节点程序中执行实际需要这些权限的操作时,才会提示用户提升权限。 次佳选择是当用户第一次启动节点程序时被提示提升权限。 最不理想的情况是,如果根本没有提示用户,则由用户始终记住通过右键单击以管理员身份运行来启动程序。这是最不理想的,因为它给用户带来了记住始终以非典型方式启动程序的负担。
所以,回到我最初的问题,现在如果我尝试生成一个子进程,其中生成的程序需要提升权限(我的原始消息中的示例代码),当前的行为是用户没有提示这些权限,而是节点程序崩溃并出现错误。我怎样才能让我的节点程序请求这些权限而不是直接死掉?
我的 nodejs 脚本:
const spawn = require('child_process');
const assoc = spawn( // how to run this as admin privileges?
'assoc', // command
['.ext=CustomExt'], // args
'shell': true // options: run this into the shell
);
assoc.stdout.on('data', (buffer) =>
var message = buffer.toString('utf8');
console.log(message);
);
assoc.stderr.on('data', (data) =>
console.log(`stderr: $data`);
);
assoc.on('close', (code) =>
console.log(`child process exited with code $code`);
);
在 Nodejs 中创建扩展关联的任何其他方式也将不胜感激。
2020 年 1 月 21 日更新
我相信 VSCode 可以做到这一点。所以我需要探索它的源代码来找到解决方案。现在在做其他项目,暂时没有时间研究。当一个文件应该以 root 权限保存时,会提示这样的消息,这正是我所需要的:
2021 年 6 月 24 日更新
我找到了useful thread in VSCode issues。使用sudo-prompt
可能是解决方案。我还没试过,但是依赖还在package.json
,所以看起来很有希望。
【问题讨论】:
你试过用管理员权限运行节点脚本吗? 是的,但这是我在@prabhat 问题中写的“最不理想”的解决方案 带管理员的节点执行?为什么我们不在批处理文件上使用 npm start 更早的管理员? 是的,但这是我在@gumuruh 问题中所写的“最不理想”的解决方案。感谢您的评论 【参考方案1】:新的和改进的答案
有关背景,请参阅旧答案中的注释。我找到了一种方法, 不必允许在用户机器上运行脚本:
import Shell from 'node-powershell'
/** Options to use when running an executable as admin */
interface RunAsAdminCommand
/** Path to the executable to run */
path: string
/** Working dir to run the executable from */
workingDir?: string
/**
* Runs a PowerShell command or an executable as admin
*
* @param command If a string is provided, it will be used as a command to
* execute in an elevated PowerShell. If an object with `path` is provided,
* the executable will be started in Run As Admin mode
*
* If providing a string for elevated PowerShell, ensure the command is parsed
* by PowerShell correctly by using an interpolated string and wrap the
* command in double quotes.
*
* Example:
*
* ```
* `"Do-The-Thing -Param '$pathToFile'"`
* ```
*/
const runAsAdmin = async (command: string | RunAsAdminCommand): Promise<string> =>
const usePowerShell = typeof command === 'string'
const shell = new Shell()
await shell.addCommand('Start-Process')
if (usePowerShell) await shell.addArgument('PowerShell')
// Elevate the process
await shell.addArgument('-Verb')
await shell.addArgument('RunAs')
// Hide the window for cleaner UX
await shell.addArgument('-WindowStyle')
await shell.addArgument('Hidden')
// Propagate output from child process
await shell.addArgument('-PassThru')
// Wait for the child process to finish before exiting
if (usePowerShell) await shell.addArgument('-Wait')
if (usePowerShell)
// Pass argument list to use in elevated PowerShell
await shell.addArgument('-ArgumentList')
await shell.addArgument(command as string)
else
// Point to executable to run
await shell.addArgument('-FilePath')
await shell.addArgument(`'$(command as RunAsAdminCommand).path'`)
if ((command as RunAsAdminCommand).workingDir)
// Point to working directory to run the executable from
await shell.addArgument('-WorkingDirectory')
await shell.addArgument(`'$(command as RunAsAdminCommand).workingDir'`)
await shell.invoke()
return await shell.dispose()
使用示例:
const unzip = async (
zipPath: string,
destinationPath: string
): Promise<string> =>
await runAsAdmin(
`"Expand-Archive -Path '$zipPath' -DestinationPath '$destinationPath'"`
)
旧答案
我不是安全专家,如果你看到这里发生了一些愚蠢的事情,请挥动红旗。
您可以在子进程中使用 PowerShell 的 Start-Process
cmdlet。您需要包含 -Verb RunAs
才能提升提示。
这将提示用户在调用 cmdlet 时允许进程以管理员身份运行。如果需要,您可以使用node-powershell
来简化操作。
以下是带有适用标志的 cmdlet 示例(只需根据需要替换 [PATH_TO_EXECUTABLE]
和 [PATH_TO_DIR_TO_RUN_FROM]
):
Start-Process -FilePath [PATH_TO_EXECUTABLE] -PassThru -Verb RunAs -WorkingDirectory [PATH_TO_DIR_TO_RUN_FROM]
警告
我们的应用程序使用打包在 Electron 应用程序中的 .ps1
文件而不是单行 PowerShell 脚本来执行此操作。在我们的案例中这不是问题,因为该应用程序是一个内部工具,因此当我们指示最终用户设置适用的 PowerShell 权限以允许运行脚本时,最终用户会信任他们。如果您不能依赖 .ps1
文件,您的里程可能会有所不同。如果您可以选择,那么Set-ExecutionPolicy
就是您的朋友。我们有用户在安装应用程序后做这样的事情:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
dir "$env:USERPROFILE\AppData\Local\Programs\path\to\our\scripts" | Unblock-File
其中$env:USERPROFILE\AppData\Local\Programs\path\to\our\scripts
指向应用程序打包的.ps1
文件目录。这样,用户只允许 PowerShell 运行我们提供给他们的脚本,而不是做一些愚蠢的事情,比如让它们允许所有 PowerShell 脚本运行而不管来源。
-ExecutionPolicy RemoteSigned
是这里的秘诀;它的意思是“仅执行来自受信任来源的下载脚本”。 (您也可以使用 -ExecutionPolicy AllSigned
来限制更多。)将脚本目录中的所有文件通过管道传输到 Unblock-File
的下一行表示“此目录中的脚本来自受信任的来源。”
【讨论】:
【参考方案2】:我知道它的旧帖子,但我遇到了这个问题并找到了一个替代解决方案,因此考虑分享。
创建一个 bat 文件,让我们将其命名为 disabletask.bat,使用您要运行的命令,例如禁用 TaskScheduler "SCHTASKS.EXE /change /disable /TN "Test"" 中的任务
在 TaskScheduler 中创建一个以最高权限运行的任务,请参阅图像中的复选框
使用 Nodejs 来执行这个任务
var child_process = require('child_process');
child_process.exec('SCHTASKS.EXE /RUN /TN "disabletask"', function(error, stdout, stderr)
console.log(stdout);
);
【讨论】:
感谢您的解决方案。但我认为解决方法有点丑哈哈 我从 VSCode 添加了一张图片。我还是没有看他们的源代码。 我在我的问题底部添加了另一个更新,我在 GitHub 中找到了一个新线程。看看它是否对你有用。以上是关于如何使用 Nodejs 和 spawn 在 Windows 10 上以管理员身份运行一些 CMD 命令?的主要内容,如果未能解决你的问题,请参考以下文章
youtube-dl nodejs 有问题 Error: spawn EACCES
nodejs child_process.spawnSync 或 child_process.spawn 包裹在 yieldable 生成器中,它返回输出