Як попросити адміністратора отримати доступ у пакетному файлі


179

Я намагаюся написати пакетний файл, щоб мої користувачі працювали зі своїх верстатів Vista з UAC. У файл перезаписується файл їх хостів, тому його потрібно запускати з правами адміністратора. Мені потрібно мати можливість надіслати їм електронний лист із посиланням на файл .bat. Бажана поведінка полягає в тому, що коли вони клацають правою кнопкою миші на файл і кажуть "Відкрити", вони отримують один із тих діалогових вікон UAC, який змушує екран затьмарювати і змушує їх відповідати, чи хочуть вони дати дозвіл програми на запуск адміністратора. Натомість вони просто бачать "Доступ заборонено" у вікні командного рядка.

Чи можливо це зробити інакше?


2
Якщо ви натрапили на це і, як я, із задоволенням використовуєте PowerShell, не пропустіть однолінійку від @ toster-cx. Ідеально!
Майкл Репуччі

Відповіді:


353

Цей сценарій робить трюк! Просто вставте його у верхню частину файлу bat. Якщо ви хочете переглянути вихід сценарію, додайте команду "пауза" внизу вашого пакетного файлу.

ОНОВЛЕННЯ: Цей сценарій тепер трохи відредагований для підтримки аргументів командного рядка та 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
Я ненавиджу робити це брудне dos дозування дурниць, але іноді тебе змушують, і це чудово працює. Ура!
матовий опік

4
Цей метод не пересилає аргументи. Чи знаєте ви, як це можна зробити? В основному те, що я зауважую, це те, що в першому рядку% 1 є якесь значення, а в останньому рядку% 1 є нульовим. Мені потрібно передати аргументи.
вигулює

3
Як і FYI, це перевірено на роботі в 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)
Pedro Duarte

Хороша відповідь. Просто працює, коли сценарій 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 і зробити пробіг та надіслати мені вихід у приватному повідомленні? Дякую!
cyberponk

У будь-якому разі, echo/%TEMP%| findstr /C:"(" >nulтести, якщо (в %temp%змінній середовищі yout є char , і слід запускати частину лише після &&позитивного. Дивно, чому ваш (тест повертається позитивно, хоча.
cyberponk

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 Explorer, але він не став, коли я запустив його з моєї 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

Це не викликає нескінченних циклів, а також видаляє перевірку привілеїв адміністратора, схильну до помилок.


Працювали для вас? На жаль, це та всі інші тут і з іншої нитки провалюються через те саме, що лежить в основі. Парм (або команда) "рунас" виходить з ладу кожного разу, коли об'єкт оболонки створений опосередковано з іншої програми. Тема інтерес тут .
Лорі Стерн

Працював для мене :)
Срітам Ягадев

6

Ще одне рішення PowerShell ...

Йдеться не про запуск пакетного сценарію як адміністратора за, а про те, як підняти іншу програму з партії ...

У мене є пакетний файл "обгортка" для exe. Вони мають те саме "ім'я кореневого файлу", але чергуються з розширеннями. Я можу запустити exe як адміністратор і встановити робочий каталог на той, що містить сценарій, із наступним викликом в одному рядку :

@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

Я знаю, що це не рішення для ОП, але оскільки я впевнений, що тут є багато інших випадків використання, я подумав, що поділюсь.

У мене були проблеми зі всіма прикладами коду в цих відповідях, але потім я знайшов: 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 та інших цікавих публікацій на цій сторінці я зрозумів, як налаштувати та вирішити свою проблему. У мене був подібний випуск, де я хотів, щоб утиліта Disk Cleanup працювала щотижня двічі в понеділок та четвер у обідні години (скажімо, 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 -c Start-Process "%~nx0" -Verb runas

-5

використовуйте команду runas. Але я не думаю, що ти можеш легко надіслати електронний лист .bat.


6
Ця відповідь невірна. runasКоманда не може бути використана , щоб викликати підйом.
Bill_Stewart
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.