无法以管理员身份运行

2024-04-16

我必须执行ewfmgr.exe仅当以管理员身份打开命令窗口时才能执行。

如果我去Start->type cmd.exe->Right click->Run as Administrator然后出现以下命令提示符窗口。在这个窗口中,如果我写ewfmgr.exe(这是我必须执行的EXE文件),然后命令执行没有任何问题。

我的要求:我的要求是通过脚本文件执行命令(RunasAdmin.cmd文件)和这个脚本文件将通过 NSIS 安装程序执行.

自从,ewfmgr.exe只能用管理员执行,所以我必须升级我的脚本才能获得管理员权限。为此,我有以下脚本:

获得管理员权限的脚本: "(RunasAdmin.cmd)"

::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
::::::::::::::::::::::::::::::::::::::::::::
 @echo off
 CLS
 ECHO.
 ECHO =============================
 ECHO Running Admin shell
 ECHO =============================

:init
 setlocal DisableDelayedExpansion
 set cmdInvoke=0
 set winSysFolder=System32
 set "batchPath=%~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 & pushd .
 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
 ewfmgr c: -enable
 pause
 cmd /k

PROBLEM:如果我执行脚本(RunasAdmin.cmd)只需双击它,脚本就会被执行并完成任务,没有任何错误。但是如果我执行脚本(RunasAdmin.cmd)通过我的 NSIS 安装程序(EWFMGR_Run.exe)然后,我收到一个错误ewfmgr is not recognised as an internal or external command

NSIS 安装程序代码: (EWFMGR_Run.exe)

OutFile "EWFMGR_Run.exe"
section
    ExecWait "D:\Disk\RunasAdmin.cmd"
sectionEnd

运行脚本后 NSIS 安装程序打开的命令窗口 (RunasAdmin.cmd)如下:

Queston:两个命令窗口均以管理员身份打开,并位于同一工作目录中。但是为什么NSIS安装程序打开的窗口找不到ewfmgr.exe?

更新1:基本上问题出在 NSIS 安装程序打开的 CMD 窗口中。即使我走向那条路C:\Windows\System32手动使用cd /D C:\Windows\System32并尝试执行ewfmgr.exe(在该路径中可用),CMD 无法识别它。

参考:提升为管理员的脚本文件取自马特的回答在这里给出。 https://stackoverflow.com/questions/7044985/how-can-i-auto-elevate-my-batch-file-so-that-it-requests-from-uac-administrator/12264592#12264592


将命令脚本(批处理文件)提升到管理员级别时至少必须考虑哪些因素?

  1. 在任何情况下当前目录都会更改为%SystemRoot%\System32.

  2. 如果当前用户不在管理员组中,则环境可能会完全改变,因此用户必须使用不同的用户帐户以管理员的提升权限运行批处理文件,例如必须使用本地管理员帐户而不是当前用户帐户。这会影响环境变量和网络资源的权限。

  3. 该脚本最初始终在 64 位 Windows 上的父进程环境中启动,如果父进程是 32 位应用程序,则在 32 位环境中启动,而不是在 64 位环境中启动。

  4. 该脚本可以使用一个或多个用双引号括起来的参数来执行,这些参数应该在以提升的权限执行时直接传递给脚本。

这4点该如何处理呢?

1.当前目录

许多命令行脚本(批处理文件)都经过编码以使用当前目录,并假设当前目录与批处理文件位于同一目录。双击本地驱动器或网络驱动器上存储的批处理文件时,当前目录与存储批处理文件的目录相同,但安全设置禁止从网络驱动器执行批处理文件。

但 Windows 设置%SystemRoot%\System32作为使用系统帐户运行 cmd 脚本作为计划任务时的当前目录。

和 Windows 套%SystemRoot%\System32作为使用时的当前目录RunAs以提升的管理员权限运行 cmd 脚本。

和 Windows 套%SystemRoot%作为当前目录打印到控制台窗口后,双击执行批处理文件时会显示以下消息,该文件存储在使用打开的网络共享上UNC path https://en.wikipedia.org/wiki/UNC_path.

'\服务器\共享\目录'
CMD.EXE 以上述路径作为当前目录启动。
不支持 UNC 路径。默认为 Windows 目录。

可以启用使用 UNC 路径作为当前目录,例如通过答案如何从网络共享运行批处理文件而不出现“不支持 UNC 路径”消息? https://stackoverflow.com/a/14278062/3074564

最好的方法是编写整个脚本代码,使其独立于当前目录的目录而工作。

这意味着不仅仅使用引用文件的文件名,而是"Full path to\FileName.exe",即带有文件扩展名和用双引号括起来的完整路径的文件名。

如果要在 cmd 脚本中运行或引用的所有文件都存储在未知文件夹中,但始终与 cmd 脚本位于同一文件夹中,则获取所有文件路径的简单方法是使用命令行:

set "SourceFolder=%~dp0"

%~dp0扩展为批处理文件的路径,始终以反斜杠结尾,并且永远不会用双引号引起来,即使文件夹路径包含空格字符或其他命令行语法关键字符(如&符号)也是如此。

然后使用引用所有文件

"%SourceFolder%FileName.exe"

Note:没有反斜杠(Windows 上的目录分隔符)作为环境变量SourceFolder保存文件夹路径,末尾带有反斜杠。

当然也可以使用cd /D "%~dp0"将当前目录设置为 cmd 脚本的目录,但这不适用于 UNC 路径。

但也有这样的命令pushd "%~dp0"如果默认启用命令扩展,也可以使用 UNC 路径。

有关命令的详细信息CD and PUSHD在命令提示符窗口中运行cd /? and pushd /?并阅读输出帮助。

2.环境变量

每当创建新进程时,Windows 都会创建当前进程当前活动环境表的副本。

但当批处理文件将自身提升到管理员级别时,情况并非如此。因此,不可能在批处理文件的初始运行时定义环境变量,然后提升到管理员级别,并现在访问之前在初始环境中定义的环境变量。甚至有可能批处理文件最初执行时是在64位Windows上的32位环境中执行的,但在提升到管理员级别后却在64位环境中运行。

因此,需要从初始执行传递到提升执行的所有内容都必须通过命令行参数或通过本地驱动器上的文件进行解析,该文件在所有环境中都可以完全访问,即每个人都可以访问。

3. 32位与64位环境

有时,32 位安装程序用于安装 32 位或 64 位应用程序,具体取决于Windows 位宽因为在所有 Windows 上运行。批处理文件是32位处理的cmd.exe在 32 位环境中使用 32 位安装程序,即使在 64 位 Windows 上执行也是如此。

在进一步阅读之前,至少应仔细研究以下三篇 Microsoft 文章:

  • 文件系统重定向器 https://learn.microsoft.com/en-us/windows/win32/winprog64/file-system-redirector
  • WOW64 实施细节 https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details
  • 受 WOW64 影响的注册表项 https://learn.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys

依赖环境变量的值绝对不是一个好主意PROCESSOR_ARCHITECTURE因为它的值是x86当 32 位进程在 32 位环境中的 64 位 Windows 上执行时。

直接从 Windows 注册表查询处理器的架构也是不好的。不保证具有 64 位 CPU 的计算机上运行 64 位 Windows。这种情况并不常见,但仍然可以在主板上配备 64 位处理器的计算机上使用 32 位 Windows。

环境变量ProgramFiles(x86)默认情况下,在 32 位 Windows 上未定义,而是在 64 位 Windows 上定义,可用于确定命令文件脚本是在 32 位还是 64 位 Windows 上运行。

还有文件%SystemRoot%\Sysnative\cmd.exe and %SystemRoot%\Sysnative\wscript.exe由于特殊别名,仅适用于在 64 位 Windows 上的 32 位执行环境中运行的 32 位进程Sysnative仅适用于 64 位 Windows 上 32 位环境中的 32 位进程。这可用于确定批处理文件当前正在哪个执行环境中运行。

4. 传递参数

无需任何参数即可轻松将执行的批处理文件提升到提升的管理员级别。

将不需要用双引号引起来的简单参数传递给运行提升的批处理文件也没有问题。

但传递一个或多个包含至少一个空格字符或这些字符之一的参数&()[]{}^=;!'+,`~<|>这需要将参数字符串括在双引号中确实不容易,尤其是从批处理文件中创建 Visual Basic 脚本以提升到管理员级别时。

尝试在批处理文件中正确编码双引号以通过 VB 脚本传递到使用提升的权限执行的同一批处理文件,这真是一场噩梦。万维网上提供的大多数解决方案根本不支持双引号参数。Matt 的 Elevate.cmd - 版本 4 https://stackoverflow.com/a/12264592/3074564也不例外。使用此代码运行批处理文件"%ProgramFiles%\Installation Folder"作为初始执行的第一个参数结果"C:\Program Files\Installation Folder"是第一个也是唯一的参数,并且在删除参数后执行提升ELEV在三个论点中C:\Program, Files\Installation and Folder.

5. 此任务的可能解决方案

对于此任务,32 位 NSIS 安装程序将调用命令行脚本,该脚本必须将自身提升到管理员级别,并且应在 64 位环境中的 64 位 Windows 上运行,而不是初始运行时的 32 位环境。

我曾经分析过批处理和VB脚本代码Matt 的 Elevate.cmd - 版本 4 https://stackoverflow.com/a/12264592/3074564,删除了所有无用的代码,增强了它以支持使用比其他发布的方法更简单的方法括在双引号中的参数,并对代码进行了完全注释,以便其他人也可以理解它以进行回答UNC 路径作为批处理文件中请求管理员权限的当前目录 https://stackoverflow.com/a/41333008/3074564.

那里发布的批处理脚本被编写为独立于当前目录工作,也可以使用 UNC 路径从网络共享执行批处理文件,当然,只有根据共享的权限设置仍然可以访问网络共享时才有效提升至管理员级别后。我今天在评论后发现Richard https://stackoverflow.com/users/6718853/richard on 他对在 Windows x64 模式下打开命令窗口的回答 https://stackoverflow.com/a/41488449/3074564该网页SS64 - 使用提升的权限运行 https://ss64.com/vb/syntax-elevate.html包含与我开发的代码几乎相同的代码,但我从未阅读过那里的代码。

下面改编的批处理文件代码应该适用于此任务。它期望可执行文件ewfmgr.exe与 cmd 脚本位于同一目录中或ewfmgr.exe在执行脚本时使用完整路径作为第一个参数指定,以防位于不同的目录中。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
cls

rem The console application NET with parameter FILE can be executed
rem successfully only if the account used for running this batch file
rem has local administrator privileges. See the Microsoft documentation
rem https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490702(v=technet.10)
rem for details about NET FILE.

rem The output written to handle STDOUT on successful execution is redirected
rem to device NUL to suppress it. The exit code of NET assigned to ERRORLEVEL
rem is in this case 0 indicating a successful execution.

rem But on a failed execution because of not having administrator
rem privileges NET outputs to handle STDERR the two error messages
rem "System error 5 has occurred." and "Access is denied." which
rem are redirected from handle STDERR to device NUL to suppress them.
rem And exit/return code of NET is 1 indicating a failed execution.

rem Read https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490982(v=technet.10))
rem for details about using command redirection operators.

%SystemRoot%\System32\net.exe FILE >nul 2>nul
if not errorlevel 1 goto RunMainCode

if "%~1" == "ELEV" (

    rem This condition is just for safety. If the batch file was started
    rem already a second time with ELEV as first parameter and execution
    rem of NET FILE failed nevertheless because of missing permissions,
    rem the batch file outputs an error message, waits for any key press
    rem by the user to make sure that the user had the chance to read the
    rem error message and then exits the batch file processing without
    rem doing anything at all.

    echo %~nx0 should run already with elevated privileges, but it isn't.
    echo(
    echo Press any key to exit %~nx0 without doing anything ...
    pause >nul
    exit /B
)

rem Define as application to run by default the file ewfmgr.exe in folder
rem of the batch file which can be a folder on a local drive or on a
rem network drive or even a UNC path.

set "AppToRun=%~dp0ewfmgr.exe"
set "BatchFileName=%~f0"
set "vbsGetPrivileges=%TEMP%\OEgetPriv_%~n0.vbs"

rem This batch file can be started without any parameter resulting in %* being
rem expanded to nothing which results in environment variable BatchArgs being
rem deleted if already existing or with ewfmgr.exe with full path as parameter
rem which must be enclosed in double quotes in case of path containing
rem one or more spaces.

rem As the batch file needs to be executed once again in a separate command
rem process running as local administrator for full access at least on local
rem machine it is necessary to prepare the parameters/arguments list. Each
rem double quote in the arguments list must be doubled to be correct escaped
rem in the VB script file.

rem This is necessary as otherwise running this batch file with
rem "Full path to\ewfmgr.exe"
rem as first parameter would result in execution of the batch file by the
rem Windows Scripting Host as Full path to\ewfmgr.exe without the double
rem quotes as arguments for the batch file and therefore the first parameter
rem is on elevated execution "Full" instead of "Full path to\ewfmgr.exe" as
rem it was initially.

rem Many "run as administrator" solutions which can be found in World Wide Web
rem don't handle parameter strings correct which are enclosed in double quotes
rem because the parameter string has one or more spaces or other critical
rem characters requiring enclosing the parameter string in double quotes.

set "BatchArgs=%*"
setlocal EnableDelayedExpansion
if defined BatchArgs set "BatchArgs= !BatchArgs:"=""!"

rem Everything output by the ECHO command lines within the next command block
rem is redirected into the VB script file created in the folder for temporary
rem files of current user with name of batch file in VB script file name. This
rem makes it possible that multiple batch files with different names can run
rem at the same time using same code for creating a VB script file to run the
rem batch file once again as administrator with elevated privileges.

rem For details on ShellExecute parameters see the Microsoft documentation
rem https://learn.microsoft.com/en-us/windows/win32/shell/shell-shellexecute

rem The tricky part is quoting the arguments list correct which should be
rem finally passed to cmd.exe executed from the VB script. The command process
rem running the batch file with elevated privileges of local administrator
rem should automatically close after execution of batch file finished which
rem is the reason for first argument /C.

rem The second argument is the command to execute by cmd.exe which is
rem the batch file name with complete path which must be enclosed in double
rem quotes for safety in case of batch file name or path contains one or more
rem spaces. But additionally the batch file itself must be started with at
rem least two more arguments.

rem The first argument for the batch file is ELEV which is used as indication
rem to detect if this batch file is already started a second time via the
rem VB script using local built-in administrator account.

rem The second argument for the batch file is the application to
rem run with full default path which is the batch file folder.

rem And last all parameters passed to this batch file on initial run should
rem be also passed to second execution of this batch file under the different
rem environment of local built-in administrator account.

rem This nesting of batch file arguments in command processor arguments written
rem into a VB script file which requires additionally escaping each double quote
rem within a string with one more double quote results in a strange syntax for
rem the line to write into the VB script file.

(
    echo Set UAC = CreateObject("Shell.Application"^)
    echo UAC.ShellExecute "%SystemRoot%\System32\cmd.exe", "/D /C """"!BatchFileName!"" ELEV ""!AppToRun!""!BatchArgs!""", , "runas", 1
) >"!vbsGetPrivileges!"
endlocal

rem Now the created VB script file can be executed with Windows Script Host.
rem That should be preferred the 64-bit wscript.exe on 64-bit Windows.
rem Then the VB script file can be deleted as no longer needed and processing
rem of this batch file under current user account ends resulting in returning
rem to command process which results in closing the console window if not
rem executed by cmd.exe started with option /K to keep the console window
rem opened like on opening a command prompt window and running this batch
rem file from within the command prompt window.

if not exist %SystemRoot%\Sysnative\WScript.exe (
    %SystemRoot%\System32\WScript.exe "%vbsGetPrivileges%"
) else %SystemRoot%\Sysnative\WScript.exe "%vbsGetPrivileges%"
del "%vbsGetPrivileges%"
exit /B


rem Here starts the main code of the batch file which needs to be
rem executed with elevated privileges of a local administrator.

rem First is checked if the first parameter of the batch file is ELEV
rem which indicates that this batch file was started a second time
rem using administrator privileges or local administrator account.

:RunMainCode
if "%~1" == "ELEV" (

    rem In this case the second argument is the application to run with
    rem batch file folder passed from initial run to this second run of
    rem the batch file. The current directory is now not anymore the initial
    rem current directory, but %SystemRoot%\System32 as set by Windows on
    rem starting a command process using RunAs and administrator account.
    rem This must be taken into account on further batch file processing.

    rem For this batch file it does not matter what is the current directory
    rem as it is written to work with path of the application to run defined
    rem on starting the batch file (initially). So there is no need to use
    rem CD /D "%~dp0"  or  PUSHD "%~dp0"  as many "run as administrator"
    rem solutions use to change the current directory to directory of the
    rem batch file. There is also no need for  CD /D "%~2"  or  PUSHD "%~2"
    rem here which of course could be also used.

    rem The two additionally added arguments ELEV and the application to
    rem run are removed from the arguments lists by using twice the
    rem command SHIFT to restore the initial arguments list.

    set "AppToRun=%~2"
    shift /1
    shift /1
)

rem The batch file could be still processed by 32-bit cmd.exe on 64-bit
rem Windows in case of an elevation was not necessary at all. Start with
rem 32-bit cmd.exe in this case the 64-bit cmd.exe for processing the batch
rem file. The 32-bit cmd.exe waits for self-termination of 64-bit cmd.exe
rem which happens on batch file processing is exited by 64-bit cmd.exe.

if not exist %SystemRoot%\Sysnative\cmd.exe goto RunApp
%SystemRoot%\Sysnative\cmd.exe /D /C ""%~f0" %*"
exit /B

rem If this batch file was started (initially) with a parameter string,
rem interpret the first parameter string as application to run with
rem full path if the specified executable file exists at all.

rem Then run the application with full path and its parameters.

:RunApp
if not "%~1" == "" (
    if exist "%~1" set "AppToRun=%~1"
)
"%AppToRun%" c: -enable
endlocal

6. 此任务的最佳解决方案

但事实证明,在我完成上面的代码的编写和测试、写下这个长答案并在发布之前阅读了由Richard https://stackoverflow.com/users/6718853/richard关于他的回答在 Windows x64 模式下打开命令窗口 https://stackoverflow.com/a/41488449/3074564,最好的解决方案很可能是使用 NSIS 代码,如发布于

如何使用 NSIS 请求管理员权限? https://stackoverflow.com/questions/8732019/

并在命令脚本中使用底部的几行也作为我的答案发布在 Windows x64 模式下打开命令窗口 https://stackoverflow.com/a/41488948/3074564从 32 位环境切换到 64 位环境。

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

无法以管理员身份运行 的相关文章

随机推荐