Как запросить доступ администратора внутри командного файла


179

Я пытаюсь написать командный файл для своих пользователей, чтобы они запускались со своих компьютеров Vista с UAC. Файл перезаписывает свой файл hosts, поэтому его необходимо запускать с разрешениями администратора. Мне нужно иметь возможность отправить им электронное письмо со ссылкой на файл .bat. Желаемое поведение состоит в том, что, когда они щелкают правой кнопкой мыши по файлу и говорят «Открыть», они получают одно из тех диалогов UAC, которое заставляет экран потемнеть и заставляет их ответить, хотят ли они дать приложению разрешение на запуск от имени администратора. Вместо этого они просто видят «Отказано в доступе» в окне командной строки.

Возможно ли это сделать по-другому?


2
Если вы сталкивались с этим и, как и я, довольны использованием PowerShell, не пропустите одну строчку из @ toster-cx. Отлично!
Майкл Репуччи

Ответы:


353

Этот скрипт делает свое дело! Просто вставьте его в верхнюю часть вашего файла летучей мыши. Если вы хотите просмотреть вывод вашего скрипта, добавьте команду «пауза» внизу вашего пакетного файла.

ОБНОВЛЕНИЕ: Этот скрипт теперь немного отредактирован для поддержки аргументов командной строки и 64-битной ОС.

Спасибо Eneerge @ https://sites.google.com/site/eneerge/scripts/batchgotadmin

@echo off

:: BatchGotAdmin
:-------------------------------------
REM  --> Check for permissions
    IF "%PROCESSOR_ARCHITECTURE%" EQU "amd64" (
>nul 2>&1 "%SYSTEMROOT%\SysWOW64\cacls.exe" "%SYSTEMROOT%\SysWOW64\config\system"
) ELSE (
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.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"
    set params= %*
    echo UAC.ShellExecute "cmd.exe", "/c ""%~s0"" %params:"=""%", "", "runas", 1 >> "%temp%\getadmin.vbs"

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

:gotAdmin
    pushd "%CD%"
    CD /D "%~dp0"
:--------------------------------------    
    <YOUR BATCH SCRIPT HERE>

22
Я ненавижу делать эту грязную глупость, но иногда вы вынуждены это делать, и это прекрасно работает. Ура!
Мэтт горит

4
Этот метод не передает аргументы. Вы знаете, как это можно сделать? По сути, я наблюдаю, что в первой строке% 1 имеет какое-то значение, а в последней строке% 1 - ноль. Мне нужно отправить аргументы.
зубцы

3
Точно так же, как к вашему сведению, это проверено на работоспособность в Windows 8 Embedded
Роберт Снайдер

6
Это бросает мою машину в спираль командных окон, которые открываются и закрываются по диагонали по экрану. Единственный способ остановить это - удалить оригинальный пакетный файл. Он многократно запускает мой командный файл и записывает файл VBS. В первый раз он запросил авторизацию, но после этого просто зацикливается.
TomDestry

2
Я столкнулся с той же проблемой, что и TomDestry с бесконечным циклом и кодом возврата 2. Это было в Windows 8.1. Я знаю, что это работало на Windows 8.0, и не могу точно сказать, было ли это обновление 8.1 или что-то еще, что вызвало проблему. Решение, которое работало для меня, состояло в том, чтобы не использовать cacls.exe (или icacls), скорее: net session> nul 2> & 1 IF ERRORLEVEL 1 goto UACPrompt ...
crig

55

Вот одна строка, которую я использовал:

@echo off
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)

echo main code here
pause

Ноты:

  • Протестировано только на Windows 7 и 10, возможно, вам придется возиться с цитированием
  • Пока не поддерживает передачу аргументов

1
Если вы знаете, сколько может быть параметров, вы можете передать параметры, включив их после того, как am_admin if not "%1"=="am_admin" (powershell start -verb runas '%0' 'am_admin "%~1" "%~2"' & exit)параметры будут на один уровень выше того, где они были
Тони Брикс,

Также возможно использовать 'am_admin %*'для передачи всего, не очень хорошо работает с кавычками и пробелами, хотя: / Вы можете использовать shiftв пакетном режиме для удаления первого аргумента, таким образом исправляя все аргументы, кроме %0.
toster-cx

Это хороший ответ, но он не должен быть принят, потому что он НЕ проверяет, был ли при первом запуске он запущен с привилегией ADMIN или нет.
Т.Тодуа

Чтобы сохранить рабочий каталог добавить cd /D %~dp0послеif not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
Педро Дуарте

Хороший ответ. Просто работает, пока скрипт VB создает бесконечный цикл, даже с разрешением на запись для% temp%.
Twonky

19

Вот мой код! Это выглядит большим, но это в основном строки комментариев (строки начинающиеся с :).

Особенности:

  • Полная переадресация аргументов
  • Не меняет рабочую папку
  • Обработка ошибок
  • Принимает пути с круглыми скобками (кроме папки% TEMP%)
  • Поддерживает UNC-пути
  • Проверка подключенной папки (предупреждает вас, если администратор не может получить доступ к подключенному диску)

  • Может использоваться как внешняя библиотека (проверьте мой пост в этой теме: https://stackoverflow.com/a/30417025/4932683 )

  • Может вызываться, когда / если нужно где-нибудь в вашем коде

Просто прикрепите это к концу вашего пакетного файла или сохраните как библиотеку (см. Выше)

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:RequestAdminElevation FilePath %* || goto:eof
:: 
:: By:   Cyberponk,     v1.5 - 10/06/2016 - Changed the admin rights test method from cacls to fltmc
::          v1.4 - 17/05/2016 - Added instructions for arguments with ! char
::          v1.3 - 01/08/2015 - Fixed not returning to original folder after elevation successful
::          v1.2 - 30/07/2015 - Added error message when running from mapped drive
::          v1.1 - 01/06/2015
:: 
:: Func: opens an admin elevation prompt. If elevated, runs everything after the function call, with elevated rights.
:: Returns: -1 if elevation was requested
::           0 if elevation was successful
::           1 if an error occured
:: 
:: USAGE:
:: If function is copied to a batch file:
::     call :RequestAdminElevation "%~dpf0" %* || goto:eof
::
:: If called as an external library (from a separate batch file):
::     set "_DeleteOnExit=0" on Options
::     (call :RequestAdminElevation "%~dpf0" %* || goto:eof) && CD /D %CD%
::
:: If called from inside another CALL, you must set "_ThisFile=%~dpf0" at the beginning of the file
::     call :RequestAdminElevation "%_ThisFile%" %* || goto:eof
::
:: If you need to use the ! char in the arguments, the calling must be done like this, and afterwards you must use %args% to get the correct arguments:
::      set "args=%* "
::      call :RequestAdminElevation .....   use one of the above but replace the %* with %args:!={a)%
::      set "args=%args:{a)=!%" 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEDELAYEDEXPANSION & set "_FilePath=%~1"
  if NOT EXIST "!_FilePath!" (echo/Read RequestAdminElevation usage information)
  :: UAC.ShellExecute only works with 8.3 filename, so use %~s1
  set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)
  :: Remove parenthesis from the temp filename
  set _FN=%_FN:(=%
  set _vbspath="%temp:~%\%_FN:)=%.vbs" & set "_batpath=%temp:~%\%_FN:)=%.bat"

  :: Test if we gave admin rights
  fltmc >nul 2>&1 || goto :_getElevation

  :: Elevation successful
  (if exist %_vbspath% ( del %_vbspath% )) & (if exist %_batpath% ( del %_batpath% )) 
  :: Set ERRORLEVEL 0, set original folder and exit
  endlocal & CD /D "%~dp1" & ver >nul & goto:eof

  :_getElevation
  echo/Requesting elevation...
  :: Try to create %_vbspath% file. If failed, exit with ERRORLEVEL 1
  echo/Set UAC = CreateObject^("Shell.Application"^) > %_vbspath% || (echo/&echo/Unable to create %_vbspath% & endlocal &md; 2>nul &goto:eof) 
  echo/UAC.ShellExecute "%_batpath%", "", "", "runas", 1 >> %_vbspath% & echo/wscript.Quit(1)>> %_vbspath%
  :: Try to create %_batpath% file. If failed, exit with ERRORLEVEL 1
  echo/@%* > "%_batpath%" || (echo/&echo/Unable to create %_batpath% & endlocal &md; 2>nul &goto:eof)
  echo/@if %%errorlevel%%==9009 (echo/^&echo/Admin user could not read the batch file. If running from a mapped drive or UNC path, check if Admin user can read it.)^&echo/^& @if %%errorlevel%% NEQ 0 pause >> "%_batpath%"

  :: Run %_vbspath%, that calls %_batpath%, that calls the original file
  %_vbspath% && (echo/&echo/Failed to run VBscript %_vbspath% &endlocal &md; 2>nul & goto:eof)

  :: Vbscript has been run, exit with ERRORLEVEL -1
  echo/&echo/Elevation was requested on a new CMD window &endlocal &fc;: 2>nul & goto:eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Пример того, как его использовать

:EXAMPLE
@echo off

 :: Run this script with elevation
 call :RequestAdminElevation "%~dpfs0" %* || goto:eof

  echo/I now have Admin rights!
  echo/
  echo/Arguments using %%args%%:    %args%
  echo/Arguments using %%*: %*
  echo/%%1= %~1
  echo/%%2= %~2
  echo/%%3= %~3

  echo/
  echo/Current Directory: %CD%
  echo/
  echo/This file: %0
  echo/

pause &goto:eof

[here you paste the RequestAdminElevation function code]

Прекрасно работает, но мне пришлось изменить строку, чтобы заставить его работать. &fc;: 2>nulВ set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)садились в ErrorLevel 1. Я извлекал , что немного , и она работала идеально. Я использую Windows 10 Home.
Knyri

У вашей папки% temp% есть круглые скобки в ее пути? Только в этом случае должен быть установлен уровень ошибки 1.
Cyberponk

Нет. Нужно ли, так fc;:как он идет: Eof сразу после? Я не уверен, почему это немного вызвало проблему, так как она должна быть выполнена.
Knyri

"fc ;: 2> nul" намеренно установить ERRORLEVEL 1 перед выходом, чтобы сигнализировать об ошибке. Не могли бы вы удалить @echo off, выполнить пробежку и отправить мне вывод в личном сообщении? Спасибо!
киберпонк

В любом случае, echo/%TEMP%| findstr /C:"(" >nulпроверяет, есть ли (в %temp%переменной окружения yout char , и должна запускать деталь только после &&положительного if. Странно, почему ваш (тест возвращается положительным, хотя.
киберпонк

7

Другой подход заключается в

  • создайте ярлык локально и установите его для вызова прав администратора (Свойства, Дополнительно, Запуск от имени администратора)

а потом

  • отправьте своим пользователям ярлык (или ссылку на ярлык, а не ссылку на сам пакетный файл).

6

Решение Бена Грипки вызывает бесконечные петли. Его партия работает так (псевдокод):

IF "no admin privileges?"
    "write a VBS that calls this batch with admin privileges"
ELSE
    "execute actual commands that require admin privileges"

Как видите, это вызывает бесконечный цикл, если VBS не может запросить права администратора.

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

Проверка в командном файле Бена Грипки просто подвержена ошибкам. Я поиграл с пакетом и заметил, что права администратора доступны, хотя проверка не удалась. Интересно, что проверка работала, как и ожидалось, если я запустил пакетный файл из проводника Windows, но это не так, когда я запустил его из моей IDE.

Поэтому я предлагаю использовать два отдельных пакетных файла. Первый генерирует VBS, который вызывает второй пакетный файл:

@echo off

echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
set params = %*:"=""
echo UAC.ShellExecute "cmd.exe", "/c ""%~dp0\my_commands.bat"" %params%", "", "runas", 1 >> "%temp%\getadmin.vbs"

"%temp%\getadmin.vbs"
del "%temp%\getadmin.vbs"

Второй, названный my_commands.bat и расположенный в том же каталоге, что и первый, содержит ваши действительные команды:

pushd "%CD%"
CD /D "%~dp0"
REM Your commands which require admin privileges here

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


Работал на тебя? К сожалению для меня, это и все остальные здесь и из другого потока терпят неудачу из-за той же самой основной проблемы. Parm (или команда) runas завершается ошибкой всякий раз, когда объект Shell создается косвенно из другой программы. Интересная нить здесь .
Лори Стерн

Работал для меня :)
Sritam Jagadev

6

Еще одно решение PowerShell ...

Речь идет не о запуске пакетного скрипта от имени администратора, а скорее о том, как поднять другую программу из пакетного ...

У меня есть пакетный файл "обертка" для exe. У них такое же «имя корневого файла», но альтернативные расширения. Я могу запустить exe-файл от имени администратора и установить рабочий каталог в каталог, содержащий скрипт, с помощью следующего однострочного вызова powershell:

@powershell "Start-Process -FilePath '%~n0.exe' -WorkingDirectory '%~dp0' -Verb RunAs"

Больше информации

Есть целый ряд дополнительных Start-Processопций, которые вы можете применить! Проверить: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-6

Обратите внимание, что я использую @префикс. Это эквивалентно @echo offодной строке. Я использую %~n0здесь, чтобы получить «корневое имя» пакетного сценария, затем объединяю его, .exeчтобы указать ему вспомогательный двоичный файл. Использование %~dp0обеспечивает полный путь к каталогу, в котором находится пакет. И, конечно же , параметр обеспечивает повышение .-Verb RunAs


4

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

У меня были проблемы со всеми примерами кода в этих ответах, но потом я нашел: http://www.robotronic.de/runasspcEn.html

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


3

@echo offи titleможет предшествовать этому коду:

net session>nul 2>&1
if %errorlevel%==0 goto main
echo CreateObject("Shell.Application").ShellExecute "%~f0", "", "", "runas">"%temp%/elevate.vbs"
"%temp%/elevate.vbs"
del "%temp%/elevate.vbs"
exit

:main
    <code goes here>
exit

Многие другие ответы излишни, если вам не нужно беспокоиться о следующем:

  • параметры
  • Рабочий каталог ( cd %~dp0изменится на каталог, содержащий пакетный файл)

3
@echo off 
Net session >nul 2>&1 || (PowerShell start -verb runas '%~0' &exit /b)
Echo Administrative privileges have been got. & pause

Выше работает на моей Windows 10 версии 1903


1

Так как у меня возникают проблемы с этим сценарием, который выдает новую командную строку с повторным запуском в бесконечном цикле (с использованием Win 7 Pro), я предлагаю вам попробовать другой подход: как я могу автоматически поднять свой пакетный файл, чтобы он запрашивал у Права администратора UAC, если требуется?

Будьте осторожны, вы должны добавить это в конце скрипта, как указано в правке, чтобы вернуться в каталог скриптов после повышения привилегий: cd / d% ~ dp0


Проверьте мой ответ на этот вопрос. Он решает все эти проблемы.
киберпонк

1

Основываясь на сообщениях Toster-CX и других интересных постах на этой странице, я получил представление о том, как настроить и решить мою проблему. У меня была похожая проблема, когда я хотел, чтобы утилита очистки диска запускалась каждую неделю дважды в понедельник и четверг в обеденное время (скажем, в 14:00). Однако это требовало повышенных прав.

Совместное использование командного файла, который может помочь другим новичкам, как я -

@echo off
echo  Welcome to scheduling 'PC Maintenance Activity'
ping localhost -n 3 >nul
echo -- Step - 1 of 3 : Please give 'Admin' rights on next screen
ping localhost -n 5 >nul
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit)
cls
echo -- Step - 2 of 3 : In next screen, select temp areas for cleaning 
during routine scheduled activity
ping localhost -n 3 >nul
C:\Windows\System32\cleanmgr.exe /sageset:112
cls
echo    Now scheduling maintenance activity...
SchTasks /Create /SC WEEKLY /D MON,THU /TN PC_Cleanup /TR 
"C:\Windows\System32\cleanmgr.exe "/sagerun:112 /ST 14:00

cls

echo                         -- Thanks for your co-operation --
echo                    -- Maintenance activity is scheduled for --
echo                       -- Every Monday and Thursday at 2 pm --

ping localhost -n 10 >nul

Большое спасибо за этот форум и Rems POST здесь [ https://www.petri.com/forums/forum/windows-scripting/general-scripting/32313-schtasks-exe-need-to-pass-parameters-to-script ] [1]

Его сообщение помогло настроить необязательный аргумент при планировании задачи.


1

Из этого поста также есть запрос FSUTIL, который также связан с ss64.com и имеет следующий код:

@Echo Off
Setlocal
:: First check if we are running As Admin/Elevated
FSUTIL dirty query %SystemDrive% >nul
if %errorlevel% EQU 0 goto START

::Create and run a temporary VBScript to elevate this batch file
   Set _batchFile=%~f0
   Set _Args=%*
   :: double up any quotes
   Set _batchFile=""%_batchFile:"=%""
   Set _Args=%_Args:"=""%

   Echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\~ElevateMe.vbs"
   Echo UAC.ShellExecute "cmd", "/c ""%_batchFile% %_Args%""", "", "runas", 1 >> "%temp%\~ElevateMe.vbs"

   cscript "%temp%\~ElevateMe.vbs" 
   Exit /B

:START
:: set the current directory to the batch file location
cd /d %~dp0
:: Place the code which requires Admin/elevation below
Echo We are now running as admin [%1] [%2]
pause

Пока FSUTIL существует, это надежная альтернатива.


0

Вы не можете запрашивать права администратора у пакетного файла, но вы можете написать сценарий хоста сценариев Windows в% temp% и запустить его (и который в свою очередь выполняет ваш пакет как администратор). Вы хотите вызвать метод ShellExecute в командной консоли. Объект приложения с "runas" в качестве глагола


0

Используйте mshtaдля запроса прав администратора:

@echo off
net session >nul 2>&1 && goto :admintasks
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', '', '', 'runas', 1);close();"
exit /b
:admintasks
rem ADMIN TASKS HERE

Или, используя powershell:

powershell -c Start-Process "%~nx0" -Verb runas

-6

используйте команду runas. Но я не думаю, что вы можете легко отправить файл .bat по электронной почте.


7
Этот ответ неверен. Команда runasне может быть использована, чтобы спровоцировать повышение.
Bill_Stewart
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.