无法以pipe理员身份运行

我必须执行ewfmgr.exe ,只有在以pipe理员身份打开命令窗口时才能执行。

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

图片http://img.zgserver.com/windows/k0subw.png

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

因为ewfmgr.exe只能用Admin来执行,所以我必须升级我的脚本才能获得pipe理权限。 为此,我有以下脚本:

获取pipe理权的脚本: "(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 

问题:如果我通过双击脚本( RunasAdmin.cmd )来执行脚本,脚本就会被执行并且完成任务而没有任何错误。 但是,如果通过我的NSIS安装程序( EWFMGR_Run.exe )执行脚本( RunasAdmin.cmd ),那么会出现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 

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

图片http://img.zgserver.com/windows/vZnI70.png

Queston:这两个命令窗口都以Admin身份打开,并进入相同的工作目录。 但是如何通过NSIS安装程序打开的窗口无法findewfmgr.exe

更新-1:基本上问题是在由NSIS安装程序打开的CMD窗口中。 即使我使用cd /DC:\Windows\System32 C:\Windows\System32手动移动到pathC:\Windows\System32并尝试执行ewfmgr.exe (可在该path中使用),CMD不会识别它。

参考文献:提升到Admin的脚本文件已经从Matt的回答中拿出来了。

尝试修改RunasAdmin.cmd以使用Sysnative而不是System32

set winSysFolder=Sysnative

我猜EWFMGR_Run.exe正在启动一个32位的cmd窗口,Windows正在试图覆盖你设置的winSysFolder = System32的强制c:\ windows \ syswow64覆盖

根据这篇文章 ,您应该使用Sysnative虚拟文件夹。

'Sysnative'文件夹

如上所述,只需在文件夹路径中插入“\ System32”,就无法从32位应用程序访问64位System32文件夹。 如果您尝试重定向到SysWOW64文件夹由系统自动进行。 但是还有另外一个文件夹名称可以使用: Sysnative

Sysnative是一个虚拟文件夹,一个特殊的别名,可用于从32位应用程序或脚本访问64位System32文件夹。 例如,如果您在应用程序的源代码中指定了这个文件夹路径:

C:\ WINDOWS \ Sysnative

实际使用以下文件夹路径:

C:\ Windows \ System32下

在将命令脚本(批处理文件)提升到管理员级别时,至少必须考虑什么?

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

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

  3. 在父进程是32位应用程序的情况下,该脚本最初总是在父进程的环境中启动,该进程在64位Windows 32位环境而不是64位环境。

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

如何处理这4点?

1.当前目录

许多命令行脚本(批处理文件)被编码为与当前目录一起工作,并假定当前目录与批处理文件是相同的目录。 除了从网络驱动器执行的批处理文件被安全设置禁用,双击当前驱动器或网络驱动器上存储的批处理文件时,当前目录与存储批处理文件的目录是相同的。

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

并且Windows使用RunAs%SystemRoot%\System32为当前目录以运行具有较高管理员权限的cmd脚本。

在打印到控制台窗口中之后,Windows将%SystemRoot%为当前目录下面的消息,执行一个批处理文件,双击存储在使用UNC路径打开的网络共享中。

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

作为当前目录使用UNC路径可以按照Microsoft支持文章KB156276中所述启用- Cmd.exe不支持UNC名称作为当前目录 。

最好的做法是编写完整的脚本代码,使其独立工作在哪个目录是当前目录。

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

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

 set "SourceFolder=%~dp0" 

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

然后所有文件都使用引用

 "%SourceFolder%FileName.exe" 

注意 :没有反斜线(Windows上的目录分隔符),因为环境变量SourceFolder保存已经带有反斜杠的文件夹路径。

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

但是,如果默认情况下启用了命令扩展,那么还有命令pushd "%~dp0"也与UNC路径一起工作。

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

2.环境变量

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

但是,批处理文件升级到管理员级别时情况并非如此。 因此,无法在批处理文件的初始运行时定义环境变量,然后升级到管理员级别,并在初始环境中访问以前定义的环境变量。 在初始执行时,甚至可能发生该批处理文件最初在64位Windows上的32位环境中执行,但在提升到管理员级别之后在64位环境中运行。

因此,所有需要从初始执行传递到高级执行的东西都必须通过命令行参数或本地驱动器上的文件进行解析,所有环境中都可以访问,即适用于所有人。

3. 32位与64位环境

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

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

  • 文件系统重定向器
  • WOW64实现细节
  • 受WOW64影响的注册表键

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

直接从Windows注册表中查询处理器的体系结构也不好。 不能保证在64位CPU的计算机上运行64位Windows。 这通常不会完成,但在主板上的64位处理器的计算机上仍然可以使用32位Windows。

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

并且文件%SystemRoot%\Sysnative\cmd.exe仅适用于在64位Windows上的32位环境中运行的32位进程,因为存在特殊的别名Sysnative仅适用于64位上的32位环境中的32位进程位Windows,可用于确定批处理文件当前在哪个环境中运行。

4.传递参数

很容易提升批处理文件执行没有任何参数提升管理员级别。

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

但是传递一个或多个包含至少一个空格字符或其中一个字符的参数并不是很容易,因为它们需要用双引号将参数字符串括起来,特别是从批处理文件中创建VBScript以提升到管理员级别。

尝试在批处理文件中对双引号进行编码,是一个真正的噩梦,通过VBScript将其传递给使用提升特权执行的相同批处理文件。 万维网中提供的大多数解决方案都不支持双引号参数。 马特的Elevate.cmd – 版本4也不例外。 使用此代码以"%ProgramFiles%\Installation Folder"作为第一个参数运行一个批处理文件,结果在"C:\Program Files\Installation Folder"中作为第一个参数进行初始执行,并且在删除参数ELEV 3个参数C:\ProgramFiles\InstallationFolder

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

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

我曾经分析过Matt的Elevate.cmd-Version 4的批处理和VBscript代码,删除了所有无用的代码,使用比双引号更简单的方法支持双引号括起来的参数,并完全评论了代码以便其他人也可以理解它作为在需要管理权限的批处理文件中作为当前目录回答UNC路径 。

在那里发布的批处理脚本被写入独立于当前目录的工作,以及使用UNC路径从网络共享执行的批处理文件的工作,当然,只有当网络共享仍然可以根据共享的权限设置提升到管理员级别后。 今天我发现了Richard 在Windows x64模式下对Open Command Window的回答后发现,网页SS64 – 使用提升权限运行包含几乎相同的代码,因为我没有阅读代码。

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

 @echo off setlocal EnableExtensions cls 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 "vbsGetPrivileges=%TEMP%\OEgetPriv_%~n0.vbs" 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 TechNet article rem https://technet.microsoft.com/en-us/library/bb490702.aspx for details rem 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://technet.microsoft.com/en-us/library/bb490982.aspx 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 goto :EOF ) 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 1 or rem 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 VBScript 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 1 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 VBScript file created in the folder for temporary rem files of current user with name of batch file in VBScript 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 VBScript file to run the rem batch file once again as administrator with elevated privileges. rem For details on ShellExecute parameters see the Microsoft MSDN article rem https://msdn.microsoft.com/en-us/library/windows/desktop/gg537745.aspx rem The tricky part is quoting the arguments list correct which should be rem finally passed to cmd.exe executed from the VBScript. 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 1 or more rem spaces. But additionally the batch file itself must be started with at rem least 2 more arguments. rem The first argument for the batch file is ELEV which is used as indication rem to detected if this batch file is already started a second time via the rem VBScript 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 VBScript 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 VBScript file. ( echo Set UAC = CreateObject^("Shell.Application"^) echo UAC.ShellExecute "%SystemRoot%\System32\cmd.exe", "/C """"%~f0"" ELEV ""!AppToRun!""!BatchArgs!""", , "runas", 1 )>"%vbsGetPrivileges%" endlocal rem Now the created VBScript file can be executed with Windows Scripting Host. rem Then the VBScript file can be deleted as not 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 open like on opening a command prompt window and running this batch rem file from within the command prompt window. %SystemRoot%\System32\WScript.exe "%vbsGetPrivileges%" del "%vbsGetPrivileges%" endlocal goto :EOF 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 has 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 ) if "%ProgramFiles(x86)%" == "" goto RunApp if not exist %SystemRoot%\Sysnative\cmd.exe goto RunApp %SystemRoot%\Sysnative\cmd.exe /C ""%~f0" %*" endlocal goto :EOF 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在他的回答中以Windows x64模式打开命令窗口的评论,最好的解决方案很可能是使用NSIS代码发布在

你如何使用NSIS请求管理员权限?

并在命令脚本中使用,只需在底部的几行也作为我的回答在Windows x64模式下打开命令窗口从32位切换到64位环境。

我想指出一个关于处理UAC和提升权利的NSIS具体方法。

如果您的NSIS安装程序需要使用提升的权限运行任何内容,则必须在您的NSIS脚本中指示如下:

 RequestExecutionLevel admin 

一旦你这样做了,当你启动安装程序,它会弹出UAC提示符,并连续不会有任何问题运行外部脚本或程序需要提升的权限。

这几乎与Mofi的答案#5一致 – 我仍然张贴这一个,因为我认为它归结为需要知道。 NSIS似乎在这里是你的表演障碍。

供参考: NSIS – 无法将更新的PATH写入HKLM