Jak Mogę automatycznie podnieść mój plik wsadowy, aby żądał od administratora UAC praw, jeśli jest to wymagane?

Chcę aby mój plik wsadowy działał tylko Jeśli nie podwyższony, należy zapewnić użytkownikowi opcję ponownego uruchomienia partii jako podwyższony.

Piszę plik wsadowy, aby ustawić zmienną systemową, skopiować dwa pliki do Program Files i uruchomić instalator sterowników. Jeśli użytkownik systemu Windows 7 / Windows Vista (UAC włączony i nawet jeśli jest lokalnym administratorem) uruchomi go bez kliknięcia prawym przyciskiem myszy i wybrania opcji "Uruchom jako Administrator", otrzyma "odmowę dostępu" kopiowanie dwóch plików i zapis zmiennej systemowej.

Chciałbym użyć polecenia do automatycznego restartu wsadu jako podwyższonego, jeśli użytkownik jest w rzeczywistości administratorem. W przeciwnym razie, jeśli nie są administratorami, chcę im powiedzieć, że potrzebują uprawnień administratora, aby uruchomić plik wsadowy. Używam xcopydo kopiowania plików i REG ADD do zapisu zmiennej systemowej. Używam tych poleceń do radzenia sobie z możliwymi maszynami z Windows XP. Znalazłem podobne pytania na ten temat, ale nic, co zajmuje się ponownym uruchomieniem pliku wsadowego jako podwyższonego.

Author: Matt, 2011-08-12

10 answers

Możesz mieć wywołanie skryptu za pomocą opcji psexec'S -h, aby uruchomić elevated.

Nie jestem pewien, jak można wykryć, czy jest już uruchomiony jako podwyższony, czy nie... może spróbuj ponownie z podwyższoną trwałością tylko wtedy, gdy jest błąd Odmowa dostępu?

Lub, możesz po prostu mieć polecenia dla xcopy i reg.exe zawsze być uruchamiane z psexec -h, ale byłoby denerwujące dla użytkownika końcowego, jeśli musi wprowadzić swoje hasło za każdym razem (lub niebezpieczne, jeśli zawarte hasło w skrypt)...

 19
Author: ewall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-12 19:04:29

Jest łatwy sposób bez konieczności używania zewnętrznego narzędzia-działa dobrze z Windows 7, 8, 8.1 i 10 i jest wstecznie kompatybilny (Windows XP nie ma żadnego UAC, więc elewacja nie jest potrzebna - w takim przypadku skrypt po prostu działa).

Zobacz ten kod (zainspirował mnie kod Nironwolfa zamieszczony w wątku plik wsadowy - "Odmowa dostępu" w Windows 7?), ale poprawiłem - w mojej wersji nie ma żadnego katalogu stworzonego i usunięte, aby sprawdzić uprawnienia administratora):

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

Skrypt wykorzystuje fakt, że NET FILE wymaga uprawnień administratora i zwraca errorlevel 1, jeśli go nie posiadasz. Podniesienie jest osiągane przez utworzenie skryptu, który ponownie uruchamia plik wsadowy w celu uzyskania uprawnień. Powoduje to, że system Windows wyświetla okno dialogowe UAC i prosi o podanie konta administratora i hasła.

Przetestowałem go z Windows 7, 8, 8.1, 10 i z Windows XP-działa dobrze dla wszystkie. Zaletą jest to, że po punkcie startowym możesz umieścić wszystko, co wymaga uprawnień administratora systemu, na przykład, jeśli zamierzasz ponownie zainstalować i ponownie uruchomić usługę Windows w celu debugowania (zakładając, że mypackage.msi jest pakietem instalatora usług):

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

Bez tego skryptu podnoszącego uprawnienia, UAC prosiłby Cię trzy razy o użytkownika administratora i hasło-teraz jesteś pytany tylko raz na początku i tylko wtedy, gdy jest to wymagane.


Jeśli twój skrypt musi po prostu pokazać komunikat o błędzie i zakończyć, jeśli nie ma żadnych uprawnień administratora zamiast automatyczne podnoszenie, jest to jeszcze prostsze: możesz to osiągnąć, dodając na początku skryptu:

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

W ten sposób użytkownik musi kliknąć prawym przyciskiem myszy i wybrać "Uruchom jako administrator". Skrypt będzie kontynuowany po instrukcji REM, Jeśli wykryje prawa administratora, w przeciwnym razie zakończy działanie z błędem. Jeśli nie potrzebujesz PAUSE, po prostu usuń to. Ważne: NET FILE [...] EXIT /D) musi być na tej samej linii. Jest on wyświetlany tutaj w wielu liniach dla lepszej czytelności!


Na niektórych maszynach napotkałem problemy, które zostały już rozwiązane w nowej wersji powyżej. Jeden był spowodowany inną obsługą podwójnego cytowania, a drugi problem był spowodowany faktem, że UAC został wyłączony (ustawiony na najniższy poziom) na komputerze z systemem Windows 7, stąd skrypt wywołuje się ponownie i ponownie.

Naprawiłem to teraz, usuwając cytaty w ścieżce i dodałem je później, a ja dodałem dodatkowy parametr, który jest dodawany, gdy skrypt ponownie uruchamia się z podwyższonymi prawami.

Podwójne cudzysłowy są usuwane przez następujące (szczegóły są tutaj):

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

Możesz następnie uzyskać dostęp do ścieżki za pomocą !batchPath!. Nie zawiera żadnych podwójnych cudzysłowów, więc można śmiało powiedzieć "!batchPath!" później w skrypcie.

Linia

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

Sprawdza, czy skrypt został już wywołany przez VBScript skrypt podnoszący prawa, dzięki czemu unikamy niekończących się rekursji. Usuwa parametr za pomocą shift.


Update:

  • Aby uniknąć konieczności rejestracji rozszerzenia .vbs W Windows 10, zastąpiłem linię
    "%temp%\OEgetPrivileges.vbs"
    by
    "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
    w skrypcie powyżej; dodano również cd /d %~dp0 zgodnie z sugestią Stephena (osobna odpowiedź) i Tomáša Zato (komentarz), aby ustawić katalog skryptów jako domyślny.

  • Teraz skrypt honoruje przekazywane do niego parametry wiersza poleceń. Podziękowania dla jxmallet, TanisDLJ i Petera Mortensena za obserwacje i inspiracje.

  • Zgodnie z podpowiedzią Artjoma B. przeanalizowałem ją i zamieniłem SHIFT na SHIFT /1, co zachowuje nazwę pliku dla parametru %0

  • Dodano del "%temp%\OEgetPrivileges_%batchName%.vbs" do sekcji :gotPrivileges, aby wyczyścić (zgodnie z sugestią mlt). Dodano %batchName%, aby uniknąć uderzenia w przypadku równoległego uruchamiania różnych partii. Zauważ, że musisz użyć for, aby być w stanie skorzystać z zaawansowanych funkcji łańcuchowych, takich jak %%~nk, które wyodrębnia tylko nazwę pliku.

  • Zoptymalizowana struktura skryptu, ulepszenia (dodana zmienna vbsGetPrivileges, do której odwołuje się teraz wszędzie, umożliwiając łatwą zmianę ścieżki lub nazwy pliku, tylko usuń plik .vbs, jeśli wsad musi być podwyższony)

  • W niektórych przypadkach wymagana była inna składnia wywołania dla elewacji. Jeśli skrypt nie działa, sprawdź następujące parametry:
    set cmdInvoke=0
    set winSysFolder=System32
    Zmień pierwszy parametr na set cmdInvoke=1 i sprawdź, czy to już rozwiązuje problem. Doda cmd.exe do skryptu wykonującego elewację.
    Lub spróbuj zmienić drugi parametr na winSysFolder=Sysnative, Może to pomóc (ale w większości przypadków nie jest wymagane) w systemach 64-bitowych. (ADBailey poinformował o tym). "Sysnative" jest wymagany tylko do uruchamiania 64-bitowych aplikacji z 32-bitowego hosta skryptów (np. procesu budowania Visual Studio lub wywołania skryptu z kolejna 32-bitowa aplikacja).

  • Aby było bardziej jasne, jak parametry są interpretowane, wyświetlam je teraz jak P1=value1 P2=value2 ... P9=value9. Jest to szczególnie przydatne, gdy trzeba załączyć parametry, takie jak ścieżki w podwójnych cudzysłowach, np. "C:\Program Files".

 295
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-20 07:14:10

Jak wspomnieli jcoder i Matt, PowerShell ułatwił to, a nawet mógł zostać osadzony w skrypcie wsadowym bez tworzenia nowego skryptu.

Zmodyfikowałem Scenariusz Matta:

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

Nie ma potrzeby stosowania etykiety :getPrivileges.

 29
Author: Ir Relevant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-29 23:47:12

Korzystam z doskonałej odpowiedzi Matta, ale widzę różnicę między moimi systemami Windows 7 i Windows 8 podczas uruchamiania skryptów podwyższonych.

Gdy skrypt zostanie podniesiony w systemie Windows 8, bieżący katalog jest ustawiony na C:\Windows\system32. Na szczęście istnieje łatwe obejście, zmieniając bieżący katalog na ścieżkę bieżącego skryptu:

cd /d %~dp0

Uwaga: Użyj cd /d, aby upewnić się, że litera dysku jest również zmieniona.

Aby to przetestować, możesz skopiować scenariusz. Uruchom normalnie w obu wersjach, aby zobaczyć ten sam wynik. Uruchom jako administrator i zobacz różnicę w 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
 27
Author: Stephen Klancher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-08 12:07:28

Robię to w ten sposób:

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

W ten sposób jest to proste i używać tylko domyślnych poleceń systemu windows. Jest to świetne, jeśli chcesz redystrybuować plik wsadowy.

CD /d %~dp0 ustawia bieżący katalog na bieżący katalog pliku (jeśli jeszcze nie jest, niezależnie od napędu, w którym znajduje się plik, dzięki opcji /d).

%~nx0 zwraca aktualną nazwę pliku z rozszerzeniem (jeśli rozszerzenie nie jest dołączone, a w folderze znajduje się exe o tej samej nazwie, wywoła exe).

Jest tak wiele odpowiedzi na ten post, że nawet nie wiem, czy moja odpowiedź będzie widoczna.

W każdym razie, uważam ten sposób prostszy niż inne rozwiązania zaproponowane na innych odpowiedziach, mam nadzieję, że komuś pomoże.

 24
Author: Matheus Rocha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-13 13:50:25

Matt ma świetną odpowiedź, ale usuwa wszelkie argumenty przekazane do scenariusza. Oto moja modyfikacja, która zachowuje argumenty. Włączyłem również poprawkę Stephena dla problemu z katalogiem roboczym w systemie 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...
 19
Author: jxmallett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-07 00:57:57

Używam PowerShella do ponownego uruchomienia skryptu, jeśli nie jest. Umieść te linie na samej górze scenariusza.

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

Skopiowałem metodę 'net name' Z odpowiedzi @ Matt. Jego odpowiedź jest znacznie lepiej udokumentowana i zawiera komunikaty o błędach i tym podobne. Ten ma tę zaletę, że PowerShell jest już zainstalowany i dostępny w systemie Windows 7 i nowszych. No temporary VBScript (*.VBS) plików i nie musisz pobierać narzędzi.

Ta metoda powinna działać bez żadnej konfiguracji lub konfiguracji, o ile uprawnienia wykonawcze PowerShell nie są zablokowane.

 16
Author: Ryan Bemrose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-29 23:52:05

Dla niektórych programów ustawiających zmienną środowiskową super secret __COMPAT_LAYER na RunAsInvoker będzie działać .Sprawdź to:

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

Chociaż w ten sposób nie będzie żadnych UAC monitujących, że użytkownik będzie kontynuował bez uprawnień administratora.

 12
Author: npocmaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-31 09:11:04

Wkleiłem to na początku skryptu:

:: 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"
:--------------------------------------
 5
Author: TanisDLJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 16:51:51

Następujący roztwór jest czysty i działa idealnie.

  1. Pobierz plik zip Elevate z https://www.winability.com/download/Elevate.zip

  2. W zip powinieneś znaleźć dwa pliki: Elevate.exe i Elevate64.exe. (Ten ostatni jest natywną kompilacją 64-bitową, jeśli tego potrzebujesz, chociaż zwykła wersja 32-bitowa, Elevate.exe, powinien działać dobrze zarówno z 32-i 64-bitową wersją systemu Windows)

  3. Skopiuj plik.exe do folderu gdzie Windows zawsze może go znaleźć (np. C:/Windows). Albo lepiej możesz skopiować w tym samym folderze, w którym planujesz zachować plik bat.

  4. Aby użyć go w pliku wsadowym, po prostu poprzedź polecenie, które chcesz wykonać jako administrator, poleceniem elevate, tak:

 elevate net start service ...
 0
Author: Vaibhav Jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-24 17:29:12