Come richiedere l'accesso come amministratore all'interno di un file batch


179

Sto cercando di scrivere un file batch affinché i miei utenti possano eseguirli dalle loro macchine Vista con UAC. Il file sta riscrivendo il file degli host, quindi deve essere eseguito con le autorizzazioni di amministratore. Devo essere in grado di inviare loro un'e-mail con un collegamento al file .bat. Il comportamento desiderato è che quando fanno clic con il pulsante destro del mouse sul file e dicono Apri, otterranno una di quelle finestre di dialogo UAC che oscurano lo schermo e li costringono a rispondere se vogliono autorizzare l'applicazione a funzionare come amministratore. Invece, stanno vedendo "Accesso negato" nella finestra della riga di comando.

È possibile fare diversamente?


2
Se ti sei imbattuto in questo e, come me, sei soddisfatto dell'uso di PowerShell, non perdere il one-liner di @ toster-cx. Perfetto!
Michael Repucci,

Risposte:


353

Questo script fa il trucco! Basta incollarlo nella parte superiore del file bat. Se si desidera rivedere l'output dello script, aggiungere un comando "pause" nella parte inferiore del file batch.

AGGIORNAMENTO: questo script è ora leggermente modificato per supportare gli argomenti della riga di comando e un sistema operativo a 64 bit.

Grazie 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
Odio dover fare questa sporca assurdità dos batch ma a volte sei costretto a farlo e funziona alla grande. Saluti!
Matt brucia il

4
Questo metodo non inoltra argomenti. Sai come si può fare? Fondamentalmente ciò che osservo è che sulla prima riga% 1 ha un valore e sull'ultima riga% 1 è nulla. Devo inoltrare gli argomenti.
regge l'

3
Proprio come un FYI questo è testato come funzionante in Windows 8 Embedded
Robert Snyder

6
Questo getta la mia macchina in una spirale di finestre di comando che si aprono e si chiudono in diagonale sullo schermo. L'unico modo per fermarlo è eliminare il file batch originale. Esegue ripetutamente il mio file batch e scrive il file vbs. La prima volta ha chiesto l'autorizzazione, ma dopo ha fatto solo un giro.
TomDestry,

2
Ho riscontrato lo stesso identico problema di TomDestry con il loop infinito e il codice di ritorno 2. Questo era su Windows 8.1. So che ha funzionato su Windows 8.0 e non posso dire con certezza se è stato l'aggiornamento 8.1 o qualcos'altro che ha causato il problema. La soluzione che ha funzionato per me è stata quella di non usare cacls.exe (o icacls), piuttosto: net session> nul 2> & 1 IF ERRORLEVEL 1 goto UACPrompt ...
crig

55

Ecco un one-liner che ho usato:

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

echo main code here
pause

Appunti:

  • Testato solo su Windows 7 e 10, potresti dover fare confusione con la quotazione
  • Per ora non supporta il passaggio di argomenti

1
Se sai quanti parametri potrebbero esserci, puoi passare i parametri includendoli dopo che am_admin if not "%1"=="am_admin" (powershell start -verb runas '%0' 'am_admin "%~1" "%~2"' & exit)I parametri saranno uno sopra dove erano
Tony Brix,

Anche possibile usare 'am_admin %*'per passare tutto, non gioca bene con virgolette e spazi: / Puoi usare shiftin batch per far uscire il primo argomento, risolvendo così tutti gli argomenti tranne %0.
toster-cx,

Questa è una buona risposta, ma non dovrebbe essere accettata, perché NON controlla se alla PRIMA esecuzione è stata eseguita con il privilegio ADMIN o meno.
T.Todua,

Per mantenere la directory di lavoro aggiungere cd /D %~dp0dopoif not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
Pedro Duarte,

Buona risposta. Funziona semplicemente mentre la cosa dello script VB crea un ciclo infinito, anche con il permesso di scrittura per% temp%.
Twonky,

19

Ecco il mio codice! Sembra grande ma sono principalmente righe di commento (le righe che iniziano con: :).

Caratteristiche:

  • Inoltro completo degli argomenti
  • Non cambia la cartella di lavoro
  • Gestione degli errori
  • Accetta percorsi con parentesi (tranne per la cartella% TEMP%)
  • Supporta percorsi UNC
  • Controllo cartella mappata (avvisa se l'amministratore non può accedere all'unità mappata)

  • Può essere usato come libreria esterna (controlla il mio post su questo argomento: https://stackoverflow.com/a/30417025/4932683 )

  • Può essere chiamato quando / se necessario in qualsiasi parte del codice

Basta allegarlo alla fine del file batch o salvarlo come libreria (controllare sopra)

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

Esempio su come usarlo

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

Funziona benissimo ma ho dovuto cambiare linea per farlo funzionare. Il &fc;: 2>nulnel set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)stava tramontando l'errorlevel a 1. ho rimosso quel po 'e ha funzionato perfetto. Sto usando Windows 10 Home.
Knyri,

La tua cartella% temp% ha una parentesi nel suo percorso? Solo in questo caso è necessario impostare il livello di errore 1.
cyberponk,

No. Ne ha bisogno fc;:poiché va: eof subito dopo? Non sono sicuro del motivo per cui quel piccolo problema abbia causato il problema, dal momento che dovrebbe essere eseguito.
Knyri,

"fc ;: 2> nul" è lì intenzionalmente per impostare ERRORLEVEL 1 prima di uscire, per segnalare un errore. Potresti rimuovere @echo off e fare una corsa e inviarmi l'output in un messaggio privato? Grazie!
cyberponk,

Ad ogni modo, echo/%TEMP%| findstr /C:"(" >nulverifica se (nella %temp%variabile di ambiente è presente un carattere e deve eseguire la parte solo &&se positivo. È strano però che il tuo (test stia tornando positivo.
cyberponk,

7

Un altro approccio è quello di

  • creare un collegamento localmente e impostarlo in modo da richiedere l'autorizzazione di amministratore (Proprietà, Avanzate, Esegui come amministratore)

e poi

  • invia ai tuoi utenti il ​​collegamento (o un collegamento al collegamento anziché uno al file batch stesso).

6

La soluzione di Ben Gripka provoca loop infiniti. Il suo batch funziona in questo modo (pseudo codice):

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

Come puoi vedere, questo provoca un ciclo infinito, se VBS non riesce a richiedere i privilegi di amministratore.

Tuttavia, può verificarsi il ciclo infinito, sebbene i privilegi di amministratore siano stati richiesti correttamente.

Il controllo nel file batch di Ben Gripka è solo soggetto a errori. Ho giocato con il batch e ho osservato che i privilegi di amministratore sono disponibili anche se il controllo non è riuscito. È interessante notare che il controllo ha funzionato come previsto, se avessi avviato il file batch da Windows Explorer, ma non quando l'ho avviato dal mio IDE.

Quindi suggerisco di usare due file batch separati. Il primo genera il VBS che chiama il secondo file batch:

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

Il secondo, chiamato "my_commands.bat" e situato nella stessa directory del primo contiene i tuoi comandi attuali:

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

Ciò non provoca loop infiniti e rimuove anche il controllo dei privilegi di amministratore soggetto a errori.


Hai lavorato per te? Purtroppo per me, questo e tutti gli altri qui e dall'altro thread falliscono a causa dello stesso problema di fondo. Il parm (o il comando) "runas" fallisce ogni volta che l'oggetto Shell viene creato indirettamente dall'interno di un altro programma. Discussione di interesse qui .
Laurie Stearn,

Ha funzionato per me :)
Sritam Jagadev il

6

Un'altra soluzione PowerShell ...

Non si tratta di eseguire uno script batch come admin per, ma piuttosto come elevare un altro programma dal batch ...

Ho un file batch "wrapper" per un exe. Hanno lo stesso "nome file root", ma estensioni alternative. Sono in grado di avviare exe come admin e impostare la directory di lavoro su quella contenente lo script, con la seguente chiamata PowerShell su una riga :

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

Ulteriori informazioni

Ci sono anche molte altre Start-Processopzioni che puoi applicare! Scopri: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-6

Nota che uso il @prefisso. Questo è equivalente a @echo offper una riga. Uso %~n0qui per ottenere il "nome root" dello script batch, quindi concateno il .exepunto per indicare il binario adiacente. L'uso di %~dp0fornisce il percorso completo alla directory in cui risiede il batch. E, naturalmente, il -Verb RunAsparametro fornisce l'elevazione .


4

So che questa non è una soluzione per OP, ma dato che sono sicuro che ci sono molti altri casi d'uso qui, ho pensato di condividere.

Ho avuto problemi con tutti gli esempi di codice in queste risposte, ma poi ho trovato: http://www.robotronic.de/runasspcEn.html

Non solo ti permette di essere eseguito come amministratore, controlla il file per assicurarsi che non sia stato manomesso e memorizza le informazioni necessarie in modo sicuro. Devo ammettere che non è lo strumento più ovvio per capire come usare, ma per quelli di noi che scrivono codice dovrebbe essere abbastanza semplice.


3

@echo offe titlepuò venire prima di questo codice:

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

Molte altre risposte sono eccessive se non devi preoccuparti di quanto segue:

  • parametri
  • Directory di lavoro ( cd %~dp0passerà alla directory contenente il file batch)

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

Quanto sopra funziona sul mio Windows 10 versione 1903


1

Dal momento che ho problemi con questo script che apre un nuovo prompt dei comandi con se stesso eseguito di nuovo, in un ciclo infinito (usando Win 7 Pro), ti suggerisco di provare un altro approccio: Come posso elevare automaticamente il mio file batch, in modo che richieda da Diritti di amministratore del Controllo account utente se richiesti?

Fai attenzione, devi aggiungerlo alla fine dello script, come indicato in una modifica, in modo da tornare alla directory degli script dopo aver elevato i privilegi: cd / d% ~ dp0


Controlla la mia risposta a questa domanda. Gestisce tutti questi problemi.
cyberponk,

1

Sulla base dei post di toster-cx e di altri post interessanti in questa pagina, ho avuto un'idea di come configurare e risolvere il mio problema. Ho avuto un problema simile in cui desideravo che l'utilità di pulizia del disco venisse eseguita ogni settimana due volte il lunedì e il giovedì durante l'ora di pranzo (diciamo alle 14:00). Tuttavia, ciò ha richiesto diritti elevati.

Condividere file batch che potrebbero aiutare altri principianti come me -

@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

Grazie mille per questo forum e Rems POST qui [ https://www.petri.com/forums/forum/windows-scripting/general-scripting/32313-schtasks-exe-need-to-pass-parameters-to-script ] [1]

Il suo post ha aiutato a configurare argomenti opzionali durante la pianificazione dell'attività.


1

C'è anche la query FSUTIL da questo post che è anche collegata a ss64.com che ha il seguente codice:

@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

Finché FSUTIL è in circolazione, è un'alternativa affidabile.


0

Non è possibile richiedere i diritti di amministratore da un file batch, ma è possibile scrivere uno script host di script di Windows in% temp% ed eseguirlo (e che a sua volta esegue il batch come amministratore) Si desidera chiamare il metodo ShellExecute in Shell. Oggetto applicazione con "runas" come verbo


0

Utilizzare mshtaper richiedere i diritti di amministratore:

@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

Oppure, usando PowerShell:

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

-6

usa il comando runas. Ma non penso che tu possa inviare facilmente un file .bat tramite e-mail.


7
Questa risposta non è corretta Il runascomando non può essere utilizzato per provocare l'elevazione.
Bill_Stewart,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.