如何自动提升我的批处理文件,以便它在需要时向 UAC 管理员权限请求?

2023-11-20

我希望我的批处理文件仅运行提升。如果未提升,请为用户提供一个选项,以在提升后重新启动批处理。

我正在编写一个批处理文件来设置系统变量,将两个文件复制到程序文件位置,然后启动驱动程序安装程序。如果 Windows 7/Windows Vista 用户 (UAC启用,即使他们是本地管理员)运行它而不右键单击并选择“以管理员身份运行”,他们将“访问被拒绝”复制两个文件并写入系统变量。

如果用户实际上是管理员,我想使用命令自动重新启动批处理。否则,如果他们不是管理员,我想告诉他们他们需要管理员权限才能运行批处理文件。我在用着xcopy复制文件并REG ADD写入系统变量。我正在使用这些命令来处理可能的 Windows XP 计算机。我在这个主题上发现了类似的问题,但没有任何涉及重新启动批处理文件的问题。


有一种简单的方法,无需使用外部工具 - 它运行良好Windows 7、8、8.1、10 和 11并且也向后兼容(Windows XP 没有任何 UAC,因此不需要提升 - 在这种情况下,脚本将继续执行)。

Check out this code (I was inspired by the code by NIronwolf posted in the thread Batch File - "Access Denied" On Windows 7? 1), but I've improved it - in my version there isn't any directory created and removed to check for administrator privileges):

::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
:: see "https://stackoverflow.com/a/12264592/1016343" for description
::::::::::::::::::::::::::::::::::::::::::::
 @echo off
 CLS
 ECHO.
 ECHO =============================
 ECHO Running Admin shell
 ECHO =============================

:init
 setlocal DisableDelayedExpansion
 set cmdInvoke=1
 set winSysFolder=System32
 set "batchPath=%~dpnx0"
 rem this works also from cmd shell, other than %~0
 for %%k in (%0) do set batchName=%%~nk
 set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs"
 setlocal EnableDelayedExpansion

:checkPrivileges
  NET FILE 1>NUL 2>NUL
  if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )

:getPrivileges
  if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
  ECHO.
  ECHO **************************************
  ECHO Invoking UAC for Privilege Escalation
  ECHO **************************************

  ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
  ECHO args = "ELEV " >> "%vbsGetPrivileges%"
  ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
  ECHO args = args ^& strArg ^& " "  >> "%vbsGetPrivileges%"
  ECHO Next >> "%vbsGetPrivileges%"
  
  if '%cmdInvoke%'=='1' goto InvokeCmd 

  ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
  goto ExecElevation

:InvokeCmd
  ECHO args = "/c """ + "!batchPath!" + """ " + args >> "%vbsGetPrivileges%"
  ECHO UAC.ShellExecute "%SystemRoot%\%winSysFolder%\cmd.exe", args, "", "runas", 1 >> "%vbsGetPrivileges%"

:ExecElevation
 "%SystemRoot%\%winSysFolder%\WScript.exe" "%vbsGetPrivileges%" %*
 exit /B

:gotPrivileges
 setlocal & cd /d %~dp0
 if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul  &  shift /1)

 ::::::::::::::::::::::::::::
 ::START
 ::::::::::::::::::::::::::::
 REM Run shell as admin (example) - put here code as you like
 ECHO %batchName% Arguments: P1=%1 P2=%2 P3=%3 P4=%4 P5=%5 P6=%6 P7=%7 P8=%8 P9=%9
 cmd /k

该脚本利用了以下事实:NET FILE需要管理员权限并返回errorlevel 1如果你没有它。提升是通过创建一个重新启动批处理文件以获取权限的脚本来实现的。这会导致 Windows 显示 UAC 对话框并要求您输入管理员帐户和密码。

我已经在 Windows 7、8、8.1、10、11 和 Windows XP 上对其进行了测试 - 它对所有系统都适用。 优点是,在启动点之后,您可以放置​​任何需要系统管理员权限的内容,例如,如果您打算重新安装并重新运行 Windows 服务以进行调试(假设 mypackage.msi 是服务安装程序包) :

msiexec /passive /x mypackage.msi
msiexec /passive /i mypackage.msi
net start myservice

如果没有此权限提升脚本,UAC 会询问您三次管理员用户名和密码 - 现在只在开始时询问一次,并且仅在需要时询问。


如果您的脚本只需要显示错误消息并在没有任何管理员权限的情况下退出代替自动提升,这甚至更简单:您可以通过在脚本开头添加以下内容来实现此目的:

@ECHO OFF & CLS & ECHO.
NET FILE 1>NUL 2>NUL & IF ERRORLEVEL 1 (ECHO You must right-click and select &
  ECHO "RUN AS ADMINISTRATOR"  to run this batch. Exiting... & ECHO. &
  PAUSE & EXIT /D)
REM ... proceed here with admin rights ...

这样,用户必须右键单击并选择“以管理员身份运行”。该脚本将在REM如果检测到管理员权限则声明,否则退出并出错。如果您不需要PAUSE,只需将其删除即可。重要的: NET FILE [...] EXIT /D)必须在同一条线上。为了更好的可读性,它在这里以多行显示!


在某些机器上,我遇到了问题,这些问题已经在上面的新版本中解决了。一个是由于不同的双引号处理,另一个问题是由于 Windows 7 计算机上的 UAC 被禁用(设置为最低级别),因此脚本一次又一次地调用自身。

我现在已经通过删除路径中的引号并稍后重新添加它们来解决此问题,并且我添加了一个额外的参数,该参数是在脚本以提升的权限重新启动时添加的。

双引号被以下删除(详细信息是here):

setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion

然后您可以使用以下方式访问该路径!batchPath!。它不包含任何双引号,所以可以肯定地说"!batchPath!"稍后在脚本中。

The line

if '%1'=='ELEV' (shift & goto gotPrivileges)

检查脚本是否已被调用VBScript脚本来提升权限,从而避免无休止的递归。它使用删除参数shift.


Update:

  • 为了避免必须注册.vbs延伸于Windows 10,我已经更换了线
    "%temp%\OEgetPrivileges.vbs"
    by
    "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
    在上面的脚本中;还添加了cd /d %~dp0按照 Stephen(单独答案)和 Tomáš Zato(评论)的建议,将脚本目录设置为默认值。

  • 现在,该脚本支持传递给它的命令行参数。感谢 jxmallet、TanisDLJ 和 Peter Mortensen 的观察和启发。

  • 根据Artjom B.的提示,我分析了它并替换了SHIFT by SHIFT /1,它保留了文件名%0范围

  • Added del "%temp%\OEgetPrivileges_%batchName%.vbs" to the :gotPrivileges要清理的部分(如mlt建议)。添加%batchName%以避免并行运行不同批次时产生影响。请注意,您需要使用for能够利用高级字符串函数,例如%%~nk,它仅提取文件名。

  • 优化脚本结构,改进(添加变量vbsGetPrivileges现在到处都可以引用它,可以轻松更改文件的路径或名称,只需删除.vbs文件(如果需要提升批次)

  • 在某些情况下,提升需要不同的调用语法。如果脚本不起作用,请检查以下参数:
    set cmdInvoke=0
    set winSysFolder=System32
    将第一个参数更改为set cmdInvoke=1并检查是否已经解决了问题。它将添加cmd.exe到执行提升的脚本。
    或者尝试将第二个参数更改为winSysFolder=Sysnative,这可能对 64 位系统有帮助(但在大多数情况下不是必需的)。 (ADBailey 已对此进行了报道)。仅当从 32 位脚本主机启动 64 位应用程序时才需要“Sysnative”(例如 Visual Studio 构建过程或从另一个 32 位应用程序调用脚本)。

  • 为了更清楚如何解释参数,我现在将其显示为P1=value1 P2=value2 ... P9=value9。如果您需要将路径等参数括在双引号中,例如"C:\Program Files".

  • 如果要调试VBS脚本,可以添加//X按照建议,将 WScript.exe 参数作为第一个参数here(它是针对 CScript.exe 进行描述的,但也适用于 WScript.exe)。

  • 错误修正由提供米格尔·安吉洛:batchPath 现在可以在 cmd shell 上正确返回。这个小脚本test.cmd显示了差异,对于那些对细节感兴趣的人(在 cmd.exe 中运行它,然后通过 Windows 资源管理器双击运行它):

    @echo off
    setlocal
    set a="%~0"
    set b="%~dpnx0"
    if %a% EQU %b% echo running shell execute
    if not %a% EQU %b% echo running cmd shell
    echo a=%a%, b=%b% 
    pause
    

有用的链接:

  • 批处理文件中特殊字符的含义:
    引号 (”), Bang (!), 插入符号 (^), , 其他特殊字符

1) Note that this link no longer exists, it is now showing a 404 error.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何自动提升我的批处理文件,以便它在需要时向 UAC 管理员权限请求? 的相关文章

  • 从其可执行文件的路径获取服务名称

    我有一个可执行文件的路径 它是一个正在运行的服务应用程序 例如 C Program Files x86 Someapp somesvc exe 我想停止并启动它 为此我想我需要获取服务的名称 如下所示 this https stackove
  • 用于推送通知的设备令牌

    我正在实施推送通知服务 我需要创建一个数据库来存储 4 个移动平台的所有设备令牌 我想根据他们的平台 iOS Android BlackBerry WP7 来组织它们 但是有什么方法可以区分平台 这样如果我只想向 Android 用户发送消
  • Qt GUI 应用程序中的控制台输出?

    我有一个在 Windows 上运行的 Qt GUI 应用程序 它允许传递命令行选项 在某些情况下我想向控制台输出一条消息 然后退出 例如 int main int argc char argv QApplication a argc arg
  • 已达到网络 BIOS 命令限制

    我的 ASP Net 应用程序从另一台 Windows 服务器上的共享文件夹获取文件 当请求增加时 我收到以下错误 The network BIOS command limit has been reached 我已按照以下步骤操作微软 K
  • Windows10上打开/创建内网Vagrant失败

    我昨天将 Windows 10 升级到了最新更新 现在启动时vagrant up命令 我收到此错误 gt default Booting VM gt default Waiting for machine to boot This may
  • 如何为 Windows toast 注册协议?

    如何注册 Windows toast 协议 样本中来自https blogs msdn microsoft com tiles and toasts 2015 07 02 adaptive and interactive toast not
  • 使用 Windows 套接字的 WriteFile 返回无效参数错误

    我已经在 Windows 套接字上苦苦挣扎了两天 无法像在 Linux 中那样只使用写入套接字 我想编写自己的 shellcode 并且正在研究如何将 stdout stdin 重定向到套接字句柄 这就是我的演奏的来源 如果有必要 我使用
  • Win 8.1 上的 XAMPP 安装带有 UAC 警告

    我正在尝试在 Windows 8 1 上安装 Xampp win32 1 8 2 我收到一条消息说 由于系统上激活的用户帐户用户帐户 XAMPP 的某些功能可能会受到限制 我尝试更改用户帐户控制设置 但警告仍然存在 并且APACHE无法启动
  • PC 相当于 Coda 吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 为什么批处理文件中的 RMDIR 作为最后一个命令没有删除文件夹?

    我的 bat 文件中有以下代码 echo off xcopy Y S CD Code Release C Users USERNAME Desktop ShareIt I cls cd C Users USERNAME Desktop Sh
  • MSI 安装程序,64 位操作系统,写入 \windows\system32\inetsrv 文件夹

    在 Windows Server 2008 64 位上 我需要一个 msi 安装程序文件来将一些文件写入 windows system32 inetsrv 文件夹 这些文件是一些 XML 架构验证文件 C XmlReaderSettings
  • 使用 Rust 构建的 DLL 在运行时是否需要 libgcc.dll?

    如果我构建一个 DLLRust 语言 http rust lang org 是否需要libgcc dll在运行时出现 一方面 我在互联网上的某个地方看到过一个帖子 声称是的 rustc exe has libgcc s dw2 1 dll在
  • x86 LargeAddressAware 兼容性的单元测试

    对于 win32 可执行文件 x86 我们可以设置 LargeAddressAware 标志 以便它在 x64 Windows 上运行时可以访问 4 GB 而不是仅 2 GB 的虚拟地址空间 这看起来很吸引人 然而 这也存在风险 例如参见
  • Powershell:获取 FQDN 主机名

    我想通过 powershell 脚本检索 Windows 服务器的 FQDN 名称 到目前为止我已经找到了2个解决方案 server Invoke Command ScriptBlock hostname 上面的行将仅打印服务器的短名称 s
  • .NET 中安全身份的本地化

    我想在 NET 中实现一个用于服务 客户端通信的命名管道 并遇到了这段代码 http code msdn microsoft com windowsdesktop CSNamedPipeCommunication 33b2485c view
  • 当调用dll函数时,参数对象的成员变量的内存地址发生变化

    类某类 一些成员MemberClass one of the mem 我有一个函数foo SomeClass object 在 dll 中 它是从 exe 调用的 Problem 地址one of the mem 在调度 dll 调用期间发
  • Apache 子进程已退出,状态为 255

    经过大量的搜索 尝试 修复 等待和哭泣 在我放弃之前 我想为这个错误抓住最后的机会 我们正在奔跑Microsoft Windows Server 2012 Apache 2 4 6 Win64 OpenSSL 1 0 1e PHP 5 5
  • 如何停止执行的 Jar 文件

    这感觉像是一个愚蠢的问题 但我似乎无法弄清楚 当我在 Windows 上运行 jar 文件时 它不会出现在任务管理器进程中 我怎样才能终止它 我已经尝试过 TASKKILL 但它对我也不起作用 On Linux ps ef grep jav
  • 如何从 Ant 启动聚合 jetty-server JAR?

    背景 免责声明 I have veryJava 经验很少 我们之前在 Ant 构建期间使用了 Jetty 6 的包装版本来处理按需静态内容 JS CSS 图像 HTML 因此我们可以使用 PhantomJS 针对 HTTP 托管环境运行单元
  • 将键码转换为相关的显示字符

    在 C Windows Forms 项目中 我有一个不提供 KeyPressed 事件的控件 它是一个 COM 控件 ESRI 映射 它仅提供 KeyUp 和 KeyDown 事件 包含关键事件参数 http msdn microsoft

随机推荐

  • 找不到强大的模块 - Node.js

    我开始使用 node j 进行开发 我遇到了有关使用 formidable 模块的问题 我有这个错误 错误 找不到模块 强大 以下是使用 npm lsinstalled 安装的模块列表 email protected email prote
  • 从命令行进行 MySQL 备份和恢复

    我正在使用命令行来备份和恢复 MYSQL 数据库 让我们使用我有一个数据库 Data1 其中包含视图和过程 当在Cmd line I use mysqldump i e gt bin gt mysqldump u root proot Da
  • CSS“content”属性中的 HTML 特殊字符

    我正在尝试使用 CSS before content 字段在项目之前添加内容 我想插入一个复选标记 但如果我在内容选项中使用它 它会打印为文字 我如何告诉 CSS 使其成为复选标记 而不是文字字符串 尝试这个 target before c
  • 如果用户 = 系统,.NET 用户设置存储在哪里?

    我一直在使用更新来更新我的一个应用程序并使用Properties Settings Default Upgrade 并发现我的更新程序重新启动我的应用程序后 它在系统用户而不是默认 登录用户下运行 这让我想知道 SYSTEM 的 user
  • 如何在 Perl 中使用变量作为正则表达式修饰符?

    我正在编写一个抽象函数 它将询问用户一个给定的问题并根据给定的正则表达式验证答案 重复该问题 直到答案与验证正则表达式匹配 但是 我还希望客户端能够指定答案是否必须区分大小写 所以像这样 sub ask my prompt validati
  • 如何检查 CachedRowSet 中是否存在列名?

    我正在从可能发生变化的视图中查询数据 在执行操作之前我需要知道该列是否存在crs get 我发现我可以查询metadata像这样在我请求数据之前查看一列是否存在 ResultSetMetaData meta crs getMetaData
  • 使用预定义的自定义键顺序数组按键对数组进行排序

    a array 0 gt a 1 gt b 2 gt c 3 gt d 我想将顺序更改为3 2 0 1 a array 3 gt d 2 gt c 0 gt a 1 gt b 如果您想以编程方式更改顺序 请查看各种PHP 中的数组排序函数
  • C# XNA 鼠标位置

    我在 XNA 中的鼠标坐标遇到一些问题 0x0 任意靠近 但不在 屏幕的左上角 我现在正在窗口模式下运行游戏 但坐标是基于屏幕的 而不是游戏窗口的 尽管 XNA 文档告诉我应该是其他情况 提前致谢 这是代码 namespace TheGam
  • MATLAB 编辑器中可以进行多光标编辑吗?

    Is there a way to multiline edit code in matlab Instead of copy paste a single line repeatedly or copy paste from matlab
  • 用连字符分隔的大小写的名称是什么?

    这是帕斯卡命名法 SomeSymbol 这是驼峰式命名法 someSymbol 这是snake case some symbol 所以我的问题是是否有一个被广泛接受的名称 some symbol 它通常用于 url 中 这个案例约定并没有真
  • C++ 时间戳到人类可读的日期时间函数

    我有一个简单的函数 我需要从时间戳返回人类可读的日期时间 但不知何故 它以秒为单位返回相同的时间戳 输入1356953890 std string UT timeStampToHReadble long timestamp const ti
  • 如何验证sqlplus可以连接?

    我想知道是否有可能获得sqlplus以某种方式输出以发现我的数据库是否已启动 我想在数据库上运行脚本列表 但在执行此操作之前 我想知道数据库是否已启动并正在使用我的脚本运行 这是我尝试过的 sqlplus DB1 lt lt EOF gt
  • 如何仅当querytext的长度等于2时才开始过滤

    如何才能仅当查询文本的长度等于 2 时才开始过滤 我有这段代码 但我不知道如何仅在 querytext length gt 2 时开始过滤
  • 关于 C 系列语言中有符号整数的使用

    当在我自己的代码中使用整数值时 我总是尝试考虑符号性 问自己整数是否应该有符号或无符号 当我确定该值永远不需要为负数时 我会使用无符号整数 我不得不说这种情况大多数时候都会发生 在阅读其他人的代码时 我很少看到无符号整数 即使表示的值不能为
  • 事件源与原始源

    我正在阅读 C WPF 书 在路由事件章节中 事件有 2 个相同的属性Source and OriginalSource 我没有看到它们之间的区别 Xaml
  • JasperReports:如何在两列中显示数据

    这是我当前的 jrxml 文件
  • Spark 流中找不到 KafkaUtils 类

    我刚刚开始使用 Spark Streaming 正在尝试构建一个示例应用程序来计算 Kafka 流中的单词数 虽然它编译的是sbt package 当我运行它时 我得到NoClassDefFoundError This post似乎有同样的
  • iPhone中使用NSData的内存泄漏问题

    内存泄漏问题 NSConcreteData to set tip photo in photo frame NSData data NSData dataWithContentsOfURL NSURL URLWithString pathO
  • 当 scipy.optimize.minimize 可能用于相同的事情时,为什么 scipy.optimize.least_squares 存在?

    我试图理解为什么scipy optimize least squares存在于scipy 该函数可用于执行模型拟合 然而 人们可以使用scipy optimize minimize做同样的事情 唯一的区别是scipy optimize le
  • 如何自动提升我的批处理文件,以便它在需要时向 UAC 管理员权限请求?

    我希望我的批处理文件仅运行提升 如果未提升 请为用户提供一个选项 以在提升后重新启动批处理 我正在编写一个批处理文件来设置系统变量 将两个文件复制到程序文件位置 然后启动驱动程序安装程序 如果 Windows 7 Windows Vista