Jak zażądać dostępu administratora do pliku wsadowego

179

Próbuję napisać plik wsadowy, aby moi użytkownicy mogli uruchamiać się z ich komputerów z systemem Vista z UAC. Plik ponownie zapisuje plik hosts, więc musi być uruchamiany z uprawnieniami administratora. Muszę mieć możliwość wysłania im e-maila z linkiem do pliku .bat. Pożądanym zachowaniem jest to, że kiedy klikną plik prawym przyciskiem myszy i powiedzą Otwórz, otrzymają jedno z tych okien dialogowych UAC, które powodują, że ekran gaśnie i zmusza ich do odpowiedzi, czy chcą zezwolić aplikacji na działanie jako administrator. Zamiast tego widzą tylko komunikat „Odmowa dostępu” w oknie wiersza poleceń.

Czy można to zrobić inaczej?

skb
źródło
2
Jeśli natrafiłeś na to i tak jak ja jesteś zadowolony z używania PowerShell, nie przegap jednej linijki z @ toster-cx. Idealny!
Michael Repucci

Odpowiedzi:

353

Ten skrypt załatwia sprawę! Po prostu wklej go na górze pliku nietoperza. Jeśli chcesz przejrzeć wyniki swojego skryptu, dodaj polecenie „wstrzymaj” na dole pliku wsadowego.

AKTUALIZACJA: Ten skrypt jest teraz nieznacznie edytowany, aby obsługiwał argumenty wiersza poleceń i 64-bitowy system operacyjny.

Dziękuję 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>
Ben Gripka
źródło
22
Nienawidzę robić tych bzdurnych bzdur partii, ale czasami jesteś do tego zmuszony i to działa świetnie. Twoje zdrowie!
Matt pali się
4
Ta metoda nie przekazuje argumentów. Czy wiesz, jak to zrobić? Zasadniczo zaobserwowałem, że w pierwszym wierszu% 1 ma jakąś wartość, aw ostatnim% 1 jest zerowe. Muszę przekazać argumenty.
zęby
3
Podobnie jak do Twojej wiadomości, test ten działa w systemie Windows 8 Embedded
Robert Snyder
6
W ten sposób moja maszyna wpada w spiralę okien sterujących, które otwierają się i zamykają ukośnie na ekranie. Jedynym sposobem, aby to zatrzymać, jest usunięcie oryginalnego pliku wsadowego. To wielokrotnie uruchamia mój plik wsadowy i zapisuje plik vbs. Za pierwszym razem poprosił o autoryzację, ale potem po prostu się zapętla.
TomDestry
2
Napotkałem dokładnie ten sam problem, co TomDestry, z nieskończoną pętlą i kodem powrotu 2. To było w systemie Windows 8.1. Wiem, że działało w systemie Windows 8.0 i nie mogę powiedzieć na pewno, czy to aktualizacja 8.1, czy coś innego spowodowało problem. Rozwiązaniem, które zadziałało, było nieużywanie cacls.exe (lub icacls), a raczej: sesja sieciowa> nul 2> & 1 IF ERRORLEVEL 1 goto UACPrompt ...
crig
55

Oto jedna linijka, której używałem:

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

echo main code here
pause

Uwagi:

  • Testowane tylko na Windows 7 i 10, być może będziesz musiał majstrować przy cytowaniu
  • Na razie nie obsługuje przekazywania argumentów
toster-cx
źródło
1
Jeśli wiesz, ile parametrów może być, możesz przekazać parametry, dodając je po. am_admin if not "%1"=="am_admin" (powershell start -verb runas '%0' 'am_admin "%~1" "%~2"' & exit)Parametry będą jeden powyżej miejsca, w którym były
Tony Brix
Można również użyć 'am_admin %*'do przekazania wszystkiego, nie działa dobrze z cudzysłowami i spacjami, chociaż: / Możesz użyć shiftwsadowo, aby usunąć pierwszy argument, naprawiając w ten sposób wszystkie argumenty z wyjątkiem %0.
toster-cx
To jest dobra odpowiedź, ale nie powinna być akceptowana, ponieważ NIE sprawdza, czy przy PIERWSZYM uruchomieniu został uruchomiony z uprawnieniami ADMINISTRATOR, czy nie.
T.Todua
Aby zachować katalog roboczy, dodaj cd /D %~dp0poif not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
Pedro Duarte
Dobra odpowiedź. Po prostu działa, podczas gdy skrypt VB tworzy nieskończoną pętlę, nawet z uprawnieniem do zapisu dla% temp%.
Twonky
19

Oto mój kod! Wygląda na duży, ale składa się głównie z wierszy komentarzy (zaczynających się od: :).

Cechy:

  • Pełne przekazywanie argumentów
  • Nie zmienia folderu roboczego
  • Obsługa błędów
  • Akceptuje ścieżki w nawiasach (z wyjątkiem folderu% TEMP%)
  • Obsługuje ścieżki UNC
  • Sprawdzanie zamapowanego folderu (ostrzega, jeśli administrator nie może uzyskać dostępu do zmapowanego dysku)

  • Może być używany jako biblioteka zewnętrzna (sprawdź mój post w tym temacie: https://stackoverflow.com/a/30417025/4932683 )

  • Można go wywołać, kiedy / w razie potrzeby, w dowolnym miejscu kodu

Po prostu dołącz to na końcu pliku wsadowego lub zapisz jako bibliotekę (sprawdź powyżej)

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

Przykład, jak go używać

: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]
cyberponk
źródło
Działa świetnie, ale musiałem zmienić linię, aby działała. &fc;: 2>nulW set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)chyliło się ERRORLEVEL do 1. usunąłem ten kawałek i to działało idealnie. Używam systemu Windows 10 Home.
Knyri
Czy twój folder% temp% ma nawias w ścieżce? Tylko w tym przypadku ma być ustawiony poziom błędu 1.
cyberponk
Nie. Czy potrzebuje fc;:skoro to idzie: eof zaraz po? Nie jestem pewien, dlaczego to trochę spowodowało problem, ponieważ powinno zostać wykonane.
Knyri
„fc ;: 2> nul” celowo ustawia ERRORLEVEL 1 przed zakończeniem, aby zasygnalizować błąd. Czy mógłbyś usunąć @echo off, wykonać bieg i wysłać mi wyniki w prywatnej wiadomości? Dzięki!
cyberponk
W każdym razie echo/%TEMP%| findstr /C:"(" >nultesty sprawdzają, czy (w %temp%zmiennej środowiskowej yout znajduje się znak , i powinny uruchamiać tylko część po &&jeśli dodatnia. (Jednak to dziwne, dlaczego wynik testu jest pozytywny.
cyberponk
7

Innym podejściem jest

  • utwórz skrót lokalnie i ustaw go tak, aby wywoływał uprawnienia administratora [Właściwości, Zaawansowane, Uruchom jako administrator]

i wtedy

  • wyślij użytkownikom skrót [lub łącze do skrótu zamiast jednego do samego pliku wsadowego].

Denis

[Dodano później - tak, nie zauważyłem daty tego wątku.]

Tryx3
źródło
6

Rozwiązanie Bena Gripki powoduje nieskończone pętle. Jego partia działa tak (pseudokod):

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

Jak widać, powoduje to nieskończoną pętlę, jeśli VBS nie zażąda uprawnień administratora.

Jednak nieskończona pętla może wystąpić, chociaż pomyślnie zażądano uprawnień administratora.

Sprawdzanie w pliku wsadowym Bena Gripki jest po prostu podatne na błędy. Bawiłem się tą partią i zauważyłem, że uprawnienia administratora są dostępne, chociaż sprawdzenie się nie powiodło. Co ciekawe, sprawdzenie działało zgodnie z oczekiwaniami, jeśli uruchomiłem plik wsadowy z eksploratora Windows, ale tak się nie stało, gdy uruchomiłem go z mojego IDE.

Dlatego sugeruję użycie dwóch oddzielnych plików wsadowych. Pierwsza generuje VBS, który wywołuje drugi plik wsadowy:

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

Drugi, o nazwie „my_commands.bat” i znajdujący się w tym samym katalogu co pierwszy, zawiera Twoje aktualne polecenia:

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

Powoduje to brak nieskończonych pętli, a także usuwa podatne na błędy sprawdzanie uprawnień administratora.

ość rybna
źródło
Pracował dla Ciebie? Niestety, ten i wszystkie inne tutaj i z drugiego wątku zawodzą z powodu tego samego podstawowego problemu. Parametr (lub polecenie) „runas” kończy się niepowodzeniem za każdym razem, gdy obiekt powłoki jest tworzony pośrednio z wnętrza innego programu. Wątek zainteresowania tutaj .
Laurie Stearn
Pracował dla mnie :)
Sritam Jagadev
6

Inne rozwiązanie PowerShell ...

Nie chodzi o uruchamianie skryptu wsadowego jako administrator, ale raczej o podniesienie poziomu innego programu z partii ...

Mam plik wsadowy „wrapper” dla exe. Mają tę samą „nazwę pliku głównego”, ale alternatywne rozszerzenia. Jestem w stanie uruchomić exe jako admin i ustawić katalog roboczy na katalog zawierający skrypt, z następującym wywołaniem PowerShell w jednym wierszu :

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

Więcej informacji

Istnieje również cała masa dodatkowych Start-Processopcji, które możesz zastosować! Sprawdź: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-6

Zauważ, że używam @przedrostka. To odpowiednik @echo offdla jednej linii. Używam %~n0tutaj, aby uzyskać "nazwę główną" skryptu wsadowego, a następnie konkatenuję, .exeaby wskazać przyległy plik binarny. Użycie narzędzia %~dp0zapewnia pełną ścieżkę do katalogu, w którym znajduje się partia. I, oczywiście, parametr zapewnia elewację .-Verb RunAs

BuvinJ
źródło
4

Wiem, że to nie jest rozwiązanie dla OP, ale ponieważ jestem pewien, że jest tu wiele innych przypadków użycia, pomyślałem, że podzielę się nimi.

Miałem problemy ze wszystkimi przykładami kodu w tych odpowiedziach, ale potem znalazłem: http://www.robotronic.de/runasspcEn.html

Nie tylko pozwala Ci działać jako administrator, ale także sprawdza plik, aby upewnić się, że nie został zmodyfikowany i bezpiecznie przechowuje potrzebne informacje. Przyznaję, że nie jest to najbardziej oczywiste narzędzie do zrozumienia, jak go używać, ale dla tych z nas, którzy piszą kod, powinno być wystarczająco proste.

trex005
źródło
3

@echo offi titlemoże pojawić się przed tym kodem:

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

Wiele innych odpowiedzi to przesada, jeśli nie musisz się martwić o następujące kwestie:

  • Parametry
  • Katalog roboczy ( cd %~dp0zmieni się na katalog zawierający plik wsadowy)
Fluorescencyjny Zielony 5
źródło
3
@echo off 
Net session >nul 2>&1 || (PowerShell start -verb runas '%~0' &exit /b)
Echo Administrative privileges have been got. & pause

Powyższe działa na moim systemie Windows 10 w wersji 1903

Matthew Wai
źródło
1

Ponieważ mam problemy z tym, że ten skrypt wyświetla nowy wiersz polecenia i uruchamia się ponownie, w nieskończonej pętli (przy użyciu Win 7 Pro), sugeruję wypróbowanie innego podejścia: Jak mogę automatycznie podwyższyć mój plik wsadowy, aby żądał od Prawa administratora UAC, jeśli są wymagane?

Uważaj, musisz dodać to na końcu skryptu, jak stwierdzono w edycji, abyś wrócił do katalogu skryptów po podniesieniu uprawnień: cd / d% ~ dp0

barbara.post
źródło
Sprawdź moją odpowiedź na to pytanie. Obsługuje wszystkie te problemy.
cyberponk
1

Na podstawie postu toster-cx i innych interesujących postów na tej stronie uzyskałem wgląd w konfigurację i rozwiązanie mojego problemu. Miałem podobny problem, gdy chciałem, aby narzędzie Oczyszczanie dysku działało co tydzień dwa razy w poniedziałek i czwartek w porze lunchu (powiedzmy o godzinie 14). Wymagało to jednak wyższych praw.

Udostępnianie pliku wsadowego, który może pomóc innym początkującym, takim jak ja -

@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

Wielkie dzięki za to forum i Rems POST tutaj [ https://www.petri.com/forums/forum/windows-scripting/general-scripting/32313-schtasks-exe-need-to-pass-parameters-to-script ] [1]

Jego post pomógł w skonfigurowaniu opcjonalnego argumentu podczas planowania zadania.

Anand
źródło
1

Istnieje również zapytanie FSUTIL z tego postu, które jest również powiązane z ss64.com i zawiera następujący kod:

@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

Tak długo, jak FSUTIL jest w pobliżu, jest to niezawodna alternatywa.

Laurie Stearn
źródło
0

Nie możesz zażądać uprawnień administratora z pliku wsadowego, ale możesz napisać skrypt hosta skryptów systemu Windows w% temp% i uruchomić go (a to z kolei spowoduje wykonanie wsadu jako administrator). Chcesz wywołać metodę ShellExecute w powłoce. Obiekt aplikacji z "runas" jako czasownikiem

Anders
źródło
0

Użyj, mshtaaby wyświetlić monit o uprawnienia administratora:

@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

Lub używając PowerShell:

powershell -c Start-Process "%~nx0" -Verb runas
HackingAddict1337
źródło
-5

użyj polecenia runas. Ale nie sądzę, aby można było łatwo wysłać plik .bat.

Josh
źródło
6
Ta odpowiedź jest nieprawidłowa. runasKomenda nie może być użyty do wywołania elewację.
Bill_Stewart