Как я могу автоматически повысить свой пакетный файл, чтобы он запрашивал права администратора UAC при необходимости?

Я хочу, чтобы мой пакетный файл запускался только с повышенными правами. Если не повышен, предоставьте пользователю возможность перезапустить пакет как повышенный.

Я пишу пакетный файл, чтобы установить системную переменную, скопируйте два файла в Program Files местоположение и запустите установщик драйверов. Если пользователь Windows 7 / Windows Vista (ОАК включено и даже если они являются локальным администратором) запускает его без щелчка правой кнопкой мыши и выбора "Запуск от имени администратора" , они получат "доступ запрещен" копирование два файла и запись системной переменной.

Я хотел бы использовать команду для автоматического перезапуска пакета с повышенными правами, если пользователь является администратором. В противном случае, если они не являются администраторами, я хочу сказать им, что им нужны права администратора для запуска пакетного файла. Я использую xcopy для копирования файлов и REG ADD для записи системной переменной. Я использую эти команды для работы с возможными машинами Windows XP. Я нашел аналогичные вопросы по этой теме, но ничего, что касается перезапуска пакетного файла с повышенными правами.

10 ответов


вы можете вызвать сам скрипт с помощью psexec ' s -h возможность запуска повышенных.

Я не уверен, как вы обнаружите, если он уже работает как повышенный или нет... может быть, повторите попытку с повышенными perms, только если есть ошибка отказа в доступе?

или, вы могли бы просто иметь команды xcopy и reg.exe всегда работать с psexec -h, но это было бы раздражает для конечного пользователя, если им нужно вводить свой пароль каждый раз (или небезопасно, если вы включили пароль в скрипт)...


существует простой способ без необходимости использовать внешний инструмент - он отлично работает с ОС Windows 7, 8, 8.1 и 10 и обратно совместим (Windows XP не имеет UAC, поэтому высота не требуется - в этом случае скрипт просто продолжается).

проверьте этот код (я был вдохновлен кодом NIronwolf, размещенным в потоке Пакетный Файл - "Доступ Запрещен" В Windows 7?), но я улучшил его - в моей версии есть не создается и не удаляется какой-либо каталог для проверки прав администратора):

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

:init
 setlocal DisableDelayedExpansion
 set cmdInvoke=1
 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 & 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 и с Windows XP - он отлично работает для всех. Преимущество заключается в том, что после начальной точки вы можете разместить все, что требует привилегий системного администратора, например, если вы собираетесь переустановить и повторно запустить службу Windows для целей отладки (предполагается, что mypackage.msi-это пакет установщика служб):

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

без этого скрипта повышения привилегий UAC попросит вас три раза для вашего пользователя и пароля администратора-теперь вас спрашивают только один раз на начало, и только при необходимости.


если ваш скрипт просто должен показать сообщение об ошибке и выйти, если нет никаких прав администратора вместо auto-elevating, это еще проще: вы можете достичь этого, добавив следующее В начале вашего скрипта:

@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) должно быть на той же линии. Он отображается здесь в нескольких строках для лучшей читаемости!


на некоторых машинах, я столкнулся с проблемами, которые решены в новой версии уже выше. Один из них был связан с другой обработкой двойной цитаты, а другая проблема была связана с тем, что UAC был отключен (установлен на самый низкий уровень) на машине Windows 7, поэтому сценарий вызывает себя снова и снова.

я исправил это сейчас, зачистив кавычки в пути и повторно добавив их позже, и я добавил дополнительный параметр, который добавляется при повторном запуске скрипта с повышенными правами.

двойные кавычки удаляются следующим образом (детали здесь):

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

вы можете получить доступ к пути с помощью !batchPath!. Он не содержит двойных кавычек, поэтому можно с уверенностью сказать "!batchPath!" позже в сценарии.

строку

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

проверяет, был ли скрипт уже вызван VBScript скрипт для повышения прав, следовательно, избежать бесконечной рекурсии. Он удаляет параметр с помощью shift.


обновление:

  • чтобы избежать необходимости регистрации


Как упоминали jcoder и Мэтт, PowerShell упростил его, и он даже может быть встроен в пакетный скрипт без создания нового скрипта.

Я изменил сценарий Мэтта:

:checkPrivileges 
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges 
) else ( powershell "saps -filepath %0 -verb runas" >nul 2>&1)
exit /b 

нет никакой необходимости :getPrivileges метки.


Я использую отличный ответ Мэтта, но я вижу разницу между моими системами Windows 7 и Windows 8 при запуске повышенных скриптов.

как только скрипт повышен в Windows 8, текущий каталог установлен в C:\Windows\system32. К счастью, есть простой обходной путь, изменив текущий каталог на путь текущего скрипта:

cd /d %~dp0

Примечание:cd /d чтобы убедиться, что буква диска изменилась.

чтобы проверить эту, в сценарий можно скопировать следующее. Нормально работать на любой версии, чтобы увидеть тот же результат. Запуск от имени администратора и увидеть разницу в Windows 8:

@echo off
echo Current path is %cd%
echo Changing directory to the path of the current script
cd %~dp0
echo Current path is %cd%
pause

Я делаю это так:

NET SESSION
IF %ERRORLEVEL% NEQ 0 GOTO ELEVATE
GOTO ADMINTASKS

:ELEVATE
CD /d %~dp0
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', '', '', 'runas', 1);close();"
EXIT

:ADMINTASKS
(Do whatever you need to do here)
EXIT

таким образом, это просто и использовать только команды windows по умолчанию. Это здорово, если вам нужно перераспределить пакетный файл.

CD /d %~dp0 устанавливает текущий каталог в текущий каталог файла (если это еще не так, независимо от диска, на котором находится файл, благодаря ).

%~nx0 возвращает текущее имя файла с расширением (если вы не включаете расширение и есть exe с тем же именем на папка, она будет вызывать exe).

есть много ответов на этот пост я даже не знаю, если мой ответ будет видно.

в любом случае, я нахожу этот способ проще, чем другие решения, предложенные на других ответах, я надеюсь, что это кому-то поможет.


Matt имеет отличный ответ, но он удаляет любые аргументы, переданные скрипту. Вот моя модификация, которая сохраняет аргументы. Я также включил исправление Стивена для Проблемы рабочего каталога в Windows 8.

@ECHO OFF
setlocal EnableDelayedExpansion

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

:getPrivileges
if '%1'=='ELEV' ( goto START )

set "batchPath=%~f0"
set "batchArgs=ELEV"

::Add quotes to the batch path, if needed
set "script=%0"
set script=%script:"=%
IF '%0'=='!script!' ( GOTO PathQuotesDone )
    set "batchPath=""%batchPath%"""
:PathQuotesDone

::Add quotes to the arguments, if needed.
:ArgLoop
IF '%1'=='' ( GOTO EndArgLoop ) else ( GOTO AddArg )
    :AddArg
    set "arg=%1"
    set arg=%arg:"=%
    IF '%1'=='!arg!' ( GOTO NoQuotes )
        set "batchArgs=%batchArgs% "%1""
        GOTO QuotesDone
        :NoQuotes
        set "batchArgs=%batchArgs% %1"
    :QuotesDone
    shift
    GOTO ArgLoop
:EndArgLoop

::Create and run the vb script to elevate the batch file
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs"
ECHO UAC.ShellExecute "cmd", "/c ""!batchPath! !batchArgs!""", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs"
"%temp%\OEgetPrivileges.vbs" 
exit /B

:START
::Remove the elevation tag and set the correct working directory
IF '%1'=='ELEV' ( shift /1 )
cd /d %~dp0

::Do your adminy thing here...

Я использую PowerShell для повторного запуска сценария с повышенными правами, если это не так. Поставьте эти строки в самом верху сценария.

net file 1>nul 2>nul && goto :run || powershell -ex unrestricted -Command "Start-Process -Verb RunAs -FilePath '%comspec%' -ArgumentList '/c %~fnx0 %*'"
goto :eof
:run
:: TODO: Put code here that needs elevation

Я скопировал метод "net name" из ответа @Matt. Его ответ гораздо лучше документирован и имеет сообщения об ошибках и тому подобное. Это имеет то преимущество, что PowerShell уже установлен и доступен в Windows 7 и выше. Нет временного VBScript (*.VBS) файлы, и вам не нужно загружать инструменты.

этот метод должен работать без любая конфигурация или настройка, если разрешения на выполнение PowerShell не заблокированы.


для некоторых программ, устанавливающих супер секрет __COMPAT_LAYER переменные среды RunAsInvoker совместимость.Проверьте это :

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

хотя, как это не будет никакого запроса UAC пользователь будет продолжать без разрешений администратора.


я вставил это в начало скрипта:

:: BatchGotAdmin
:-------------------------------------
REM  --> Check for permissions
>nul 2>&1 "%SYSTEMROOT%\system32\icacls.exe" "%SYSTEMROOT%\system32\config\system"

REM --> If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
    echo Requesting administrative privileges...
    goto UACPrompt
) else ( goto gotAdmin )

:UACPrompt
    echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
    echo args = "" >> "%temp%\getadmin.vbs"
    echo For Each strArg in WScript.Arguments >> "%temp%\getadmin.vbs"
    echo args = args ^& strArg ^& " "  >> "%temp%\getadmin.vbs"
    echo Next >> "%temp%\getadmin.vbs"
    echo UAC.ShellExecute "%~s0", args, "", "runas", 1 >> "%temp%\getadmin.vbs"

    "%temp%\getadmin.vbs" %*
    exit /B

:gotAdmin
    if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
    pushd "%CD%"
    CD /D "%~dp0"
:--------------------------------------

следующее решение чисто и работает отлично.

  1. скачать поднять zip-файл изhttps://www.winability.com/download/Elevate.zip

  2. внутри zip вы должны найти два файла: Elevate.exe и Elevate64.исполняемый. (Последний является собственной 64-разрядной компиляцией, если вам это требуется, хотя обычная 32-разрядная версия повышается.exe, должен отлично работать как с 32 -, так и с 64-разрядными версиями Windows)

  3. скопируйте файл Elevate.exe в папку, где Windows всегда может найти его (например, C:/Windows). Или вы лучше можете скопировать в ту же папку, где вы планируете сохранить файл bat.

  4. чтобы использовать его в пакетном файле, просто добавьте команду, которую вы хотите выполнить как администратор, с помощью команды elevate, например:

 elevate net start service ...