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

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

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

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

Ответ 1

Вы можете использовать вызов script psexec -h для запуска повышенного уровня.

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

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

Ответ 2

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

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

::::::::::::::::::::::::::::::::::::::::::::
:: 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=%~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 трижды запросил бы у вас имя пользователя и пароль администратора - теперь вас спрашивают только один раз в начале и только при необходимости.


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

@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.


Обновить:

  • Чтобы избежать необходимости регистрировать расширение .vbs в Windows 10, я заменил строку
    "%temp%\OEgetPrivileges.vbs"
    от
    "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
    в сценарии выше; также добавил cd/d %~dp0 как предложили Стивен (отдельный ответ) и Томаш Зато (комментарий), чтобы установить каталог скриптов по умолчанию.

  • Теперь скрипт учитывает передаваемые ему параметры командной строки. Спасибо jxmallet, TanisDLJ и Питеру Мортенсену за наблюдения и вдохновение.

  • Согласно подсказке Artjom B., я проанализировал ее и заменил SHIFT на SHIFT/1, в котором имя файла сохраняется для параметра %0

  • Добавил del "%temp%\OEgetPrivileges_%batchName%.vbs" в раздел :gotPrivileges для очистки (как предложено в mlt). Добавлен %batchName% чтобы избежать влияния при параллельном запуске разных пакетов. Обратите внимание, что вам нужно использовать for, чтобы иметь возможность воспользоваться преимуществами передовых строковых функций, таких как %%~nk, который извлекает только имя файла.

  • Оптимизированная структура скрипта, улучшения (добавлена переменная vbsGetPrivileges которую теперь ссылаются все, что позволяет легко изменять путь или имя файла, удаляйте только файл .vbs если необходимо .vbs пакет)

  • В некоторых случаях для повышения прав потребовался другой синтаксис вызова. Если скрипт не работает, проверьте следующие параметры:
    set cmdInvoke=0
    set winSysFolder=System32
    Либо измените 1-й параметр, чтобы set cmdInvoke=1 и проверьте, устраняет ли это уже проблему. Это добавит cmd.exe в скрипт, выполняющий повышение прав.
    Или попробуйте изменить второй параметр на winSysFolder=Sysnative, это может помочь (но в большинстве случаев не требуется) в 64-разрядных системах. (ADBailey сообщил об этом). "Sysnative" требуется только для запуска 64-разрядных приложений с 32-разрядного хоста сценария (например, процесс сборки Visual Studio или вызов сценария из другого 32-разрядного приложения).

  • Чтобы было более понятно, как интерпретируются параметры, я теперь отображаю это как P1=value1 P2=value2... P9=value9. Это особенно полезно, если вам нужно заключить такие параметры, как пути, в двойные кавычки, например, "C:\Program Files".

Полезные ссылки:

Ответ 3

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

Я модифицировал Matt script:

: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.

Ответ 4

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

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

cd /d %~dp0

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

Чтобы проверить это, вы можете скопировать следующее в script. Запустите нормально в любой версии, чтобы увидеть тот же результат. Запустите администратор и посмотрите разницу в 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

Ответ 5

Я делаю так:

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 Устанавливает текущий каталог в текущий каталог файла (если он еще не существует, независимо от того, какой диск находится в файле, благодаря опции /d).

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

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

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

Ответ 6

У Мэтта есть отличный ответ, но он удаляет любые аргументы, переданные в script. Вот моя модификация, которая содержит аргументы. Я также включил Stephen исправление проблемы рабочего каталога в 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...

Ответ 7

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

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 не заблокированы.

Ответ 8

Для некоторых программ установка сверхсекретной переменной __COMPAT_LAYER для среды RunAsInvoker будет работать.Проверьте это:

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

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

Ответ 9

Я вставил это в начале script:

:: 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"
:--------------------------------------

Ответ 10

Хотя это не относится непосредственно к этому вопросу, потому что он хочет получить некоторую информацию для пользователя, Google привел меня сюда, когда я хотел запустить мой файл .bat с повышенными правами из планировщика задач.

Простейшим подходом было создание ярлыка для файла .bat, потому что для ярлыка вы можете установить Run as administrator непосредственно из расширенных свойств.

Запустив ярлык из планировщика задач, запустим файл .bat с повышенными правами.

Ответ 11

Следующее решение является чистым и работает отлично.

  1. Загрузите почтовый файл Elevate по адресу https://www.winability.com/download/Elevate.zip

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

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

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

 elevate net start service ...