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

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

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

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

186 голосов | спросил PDixon724 12 PM000000100000001331 2011, 22:55:13

10 ответов


0

Вы можете сделать так, чтобы скрипт сам вызывал с помощью psexec -h для запуска с повышенными правами.

Я не уверен, как вы могли бы определить, работает ли он с повышенными правами или нет ... может быть, повторите попытку с повышенными привилегиями только в случае ошибки «Отказано в доступе»?

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

ответил ewall 12 PM000000110000002931 2011, 23:04:29
0

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

Проверьте этот код (я был вдохновлен кодом, написанным NIronwolf в теме Пакетный файл -« Доступ запрещен »в 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 и Питеру Мортенсену за наблюдения и вдохновение.

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

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

  • Оптимизированная структура скрипта, улучшения (добавлена ​​переменная vbsGetPrivileges, на которую теперь ссылаются везде, позволяя изменить путь или имя файл легко, только удалите файл .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"

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

ответил Matt 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowTue, 04 Sep 2012 17:31:50 +0400 2012, 17:31:50
0

Как отметили jcoder и Matt, 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 нет необходимости.

ответил Ir Relevant 10 J000000Thursday14 2014, 03:22:02
0

Я использую отличный ответ Мэтта, но я вижу разницу между моими системами 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
ответил Stephen Klancher 4 AM00000020000000031 2013, 02:35:00
0

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

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

На это сообщение так много ответов, что я даже не знаю, будет ли мой ответ увиденным.

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

ответил Matheus Rocha 7 J0000006Europe/Moscow 2016, 05:40:59
0

У Мэтта отличный ответ, но он отбрасывает все аргументы, переданные сценарию. Вот моя модификация, которая сохраняет аргументы. Я также включил исправление Стивена для проблемы с рабочим каталогом в 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...
ответил jxmallett 12 FebruaryEurope/MoscowbThu, 12 Feb 2015 03:43:35 +0300000000amThu, 12 Feb 2015 03:43:35 +030015 2015, 03:43:35
0

Я использую 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 не заблокированы.

ответил Ryan Bemrose 10 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 10 Sep 2014 07:28:55 +0400 2014, 07:28:55
0

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

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

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

ответил npocmaka 29 MarpmTue, 29 Mar 2016 21:55:11 +03002016-03-29T21:55:11+03:0009 2016, 21:55:11
0

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

:: 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"
:--------------------------------------
ответил TanisDLJ 11 PM000000120000004231 2014, 12:02:42
0

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

  1. Загрузите ZIP-файл 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 ...
ответил Vaibhav Jain 24 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 24 Sep 2018 20:29:12 +0300 2018, 20:29:12

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132