Comment demander l'accès administrateur dans un fichier batch

186

J'essaie d'écrire un fichier batch pour que mes utilisateurs s'exécutent à partir de leurs machines Vista avec UAC. Le fichier réécrit son fichier d'hôtes, il doit donc être exécuté avec les autorisations d'administrateur. Je dois pouvoir leur envoyer un e-mail avec un lien vers le fichier .bat. Le comportement souhaité est que lorsqu'ils cliquent avec le bouton droit sur le fichier et disent Ouvrir, ils obtiennent l'une de ces boîtes de dialogue UAC qui assombrissent l'écran et les obligent à répondre s'ils veulent donner à l'application l'autorisation de s'exécuter en tant qu'administrateur. Au lieu de cela, ils voient simplement "Accès refusé" dans la fenêtre de ligne de commande.

Est-ce possible de faire différemment?

skb
la source
2
Si vous êtes tombé sur ceci et, comme moi, êtes satisfait de l'utilisation de PowerShell, ne manquez pas le one-liner de @ toster-cx. Parfait!
Michael Repucci

Réponses:

363

Ce script fait l'affaire! Collez-le simplement en haut de votre fichier chauve-souris. Si vous souhaitez revoir la sortie de votre script, ajoutez une commande "pause" au bas de votre fichier batch.

MISE À JOUR: Ce script est maintenant légèrement modifié pour prendre en charge les arguments de ligne de commande et un système d'exploitation 64 bits.

Merci 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
la source
22
Je déteste avoir à faire ce sale dos de bêtises, mais parfois vous y êtes obligé et cela fonctionne très bien. À votre santé!
matt brûle
4
Cette méthode ne transfère pas d'arguments. Savez-vous comment cela peut être fait? Fondamentalement, ce que j'observe, c'est que sur la première ligne,% 1 a une valeur et sur la dernière ligne,% 1 est nul. J'ai besoin de transmettre les arguments.
prongs
3
Tout comme un FYI, cela est testé comme fonctionnant dans Windows 8 Embedded
Robert Snyder
6
Cela jette ma machine dans une spirale de fenêtres de commande s'ouvrant et se fermant en diagonale sur l'écran. La seule façon de l'arrêter est de supprimer le fichier de commandes d'origine. Il exécute à plusieurs reprises mon fichier de commandes et écrit le fichier vbs. La première fois, il a demandé une autorisation, mais après cela, il ne fait qu'une boucle.
TomDestry
2
J'ai rencontré exactement le même problème que TomDestry avec la boucle infinie et le code de retour 2. C'était sous Windows 8.1. Je sais que cela a fonctionné sur Windows 8.0 et je ne peux pas dire avec certitude si c'était la mise à jour 8.1 ou autre chose qui a causé le problème. La solution qui a fonctionné pour moi était de ne pas utiliser cacls.exe (ou icacls), mais plutôt: net session> nul 2> & 1 IF ERRORLEVEL 1 goto UACPrompt ...
crig
58

Voici un one-liner que j'utilise:

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

echo main code here
pause

Remarques:

  • Uniquement testé sur Windows 7 et 10, vous devrez peut-être déranger le devis
  • Ne prend pas en charge la transmission d'arguments pour le moment
toster-cx
la source
1
Si vous savez combien de paramètres il pourrait y avoir, vous pouvez passer des paramètres en les incluant après am_admin if not "%1"=="am_admin" (powershell start -verb runas '%0' 'am_admin "%~1" "%~2"' & exit)Les paramètres seront l'un au-dessus de l'endroit où ils se trouvaient
Tony Brix
Également possible d'utiliser 'am_admin %*'pour tout passer, ne joue pas bien avec les guillemets et les espaces tho: / Vous pouvez utiliser shiften batch pour faire sauter le premier argument, corrigeant ainsi tous les arguments sauf %0.
toster-cx
C'est une bonne réponse, mais ne devrait pas être acceptée, car elle NE vérifie PAS si lors de la PREMIÈRE exécution, elle a été exécutée avec le privilège ADMIN ou non.
T.Todua
Pour garder le répertoire de travail ajouter cd /D %~dp0aprèsif not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
Pedro Duarte
Bonne réponse. Fonctionne simplement pendant que le script VB crée une boucle infinie, même avec l'autorisation d'écriture pour% temp%.
Twonky
19

Voici mon code! Cela a l'air gros mais ce sont surtout des lignes de commentaires (les lignes commençant par: :).

Fonctionnalités:

  • Transfert complet des arguments
  • Ne change pas le dossier de travail
  • La gestion des erreurs
  • Accepte les chemins avec parenthèses (sauf pour le dossier% TEMP%)
  • Prend en charge les chemins UNC
  • Vérification du dossier mappé (vous avertit si l'administrateur ne peut pas accéder au lecteur mappé)

  • Peut être utilisé comme bibliothèque externe (consultez mon article à ce sujet: https://stackoverflow.com/a/30417025/4932683 )

  • Peut être appelé quand / si nécessaire n'importe où dans votre code

Attachez-le simplement à la fin de votre fichier batch ou enregistrez-le en tant que bibliothèque (vérifiez ci-dessus)

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

Exemple d'utilisation

: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
la source
Fonctionne très bien mais j'ai dû changer une ligne pour que cela fonctionne. Le &fc;: 2>nuldans set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)définissait le niveau d'erreur à 1. J'ai supprimé ce bit et cela a fonctionné parfaitement. J'utilise Windows 10 Famille.
Knyri
Votre dossier% temp% a-t-il des parenthèses dans son chemin? Seulement dans ce cas, le niveau d'erreur 1 est censé être défini.
cyberponk
Nan. A-t-il besoin du fc;:puisqu'il va: eof juste après? Je ne sais pas non plus pourquoi ce petit élément a causé le problème, car il devrait être exécuté.
Knyri
"fc ;: 2> nul" est là pour régler intentionnellement ERRORLEVEL 1 avant de quitter, pour signaler une erreur. Pourriez-vous s'il vous plaît supprimer le @echo et faire une course et m'envoyer la sortie dans un message privé? Merci!
cyberponk
Quoi qu'il en soit, les echo/%TEMP%| findstr /C:"(" >nultests s'il y a un caractère (dans votre %temp%variable d'environnement et ne devraient exécuter la partie qu'après le &&si positif. (Cependant, il est étrange que votre test soit positif.
cyberponk
7

Une autre approche consiste à

  • créez un raccourci localement et configurez-le pour demander l'autorisation d'administrateur (Propriétés, Avancé, Exécuter en tant qu'administrateur)

puis

  • envoyer à vos utilisateurs le raccourci (ou un lien vers le raccourci plutôt qu'un lien vers le fichier de commandes lui-même).
Tryx3
la source
6

La solution de Ben Gripka provoque des boucles infinies. Son lot fonctionne comme ceci (pseudo code):

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

Comme vous pouvez le voir, cela provoque une boucle infinie, si le VBS échoue à demander les privilèges d'administrateur.

Cependant, la boucle infinie peut se produire, bien que les privilèges d'administrateur aient été demandés avec succès.

L'enregistrement dans le fichier batch de Ben Gripka est juste sujet aux erreurs. J'ai joué avec le lot et observé que les privilèges d'administrateur sont disponibles bien que la vérification ait échoué. Fait intéressant, la vérification a fonctionné comme prévu, si j'ai démarré le fichier de commandes à partir de l'explorateur Windows, mais ce n'est pas le cas lorsque je l'ai démarré à partir de mon IDE.

Je suggère donc d'utiliser deux fichiers batch séparés. Le premier génère le VBS qui appelle le deuxième fichier 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"

Le second, nommé "my_commands.bat" et situé dans le même répertoire que le premier contient vos commandes réelles:

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

Cela ne provoque pas de boucles infinies et supprime également la vérification des privilèges d'administrateur sujette aux erreurs.

arête de poisson
la source
Avez-vous travaillé pour vous? Malheureusement pour moi, ceci et tous les autres ici et de l' autre fil échouent à cause du même problème sous-jacent. Le parm (ou commande) "runas" échoue chaque fois que l'objet Shell est créé indirectement à partir d'un autre programme. Sujet d'intérêt ici .
Laurie Stearn
A travaillé pour moi :)
Sritam Jagadev
6

Une autre solution PowerShell ...

Il ne s'agit pas d'exécuter un script batch en tant qu'administrateur, mais plutôt de savoir comment élever un autre programme du batch ...

J'ai un fichier batch "wrapper" pour un exe. Ils ont le même "nom de fichier racine", mais des extensions alternatives. Je suis capable de lancer l'exe en tant qu'administrateur et de définir le répertoire de travail sur celui contenant le script, avec l' invocation PowerShell d' une ligne suivante :

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

Plus d'informations

Il existe également toute une série d' Start-Processoptions supplémentaires que vous pouvez appliquer! Découvrez: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-6

Notez que j'utilise le @préfixe. C'est équivalent à @echo offpour une ligne. J'utilise %~n0ici pour obtenir le "nom racine" du script batch, puis je concatène le .exepour le pointer vers le binaire adjacent. L'utilisation de %~dp0fournit le chemin d'accès complet au répertoire dans lequel réside le lot. Et, bien sûr, le -Verb RunAsparamètre fournit l'élévation .

BuvinJ
la source
4

Je sais que ce n'est pas une solution pour OP, mais comme je suis sûr qu'il existe de nombreux autres cas d'utilisation ici, j'ai pensé partager.

J'ai eu des problèmes avec tous les exemples de code dans ces réponses, mais j'ai trouvé: http://www.robotronic.de/runasspcEn.html

Il vous permet non seulement d'exécuter en tant qu'administrateur, mais il vérifie le fichier pour s'assurer qu'il n'a pas été falsifié et stocke les informations nécessaires en toute sécurité. J'admets que ce n'est pas l'outil le plus évident pour comprendre comment l'utiliser, mais pour ceux d'entre nous qui écrivent du code, cela devrait être assez simple.

trex005
la source
3

@echo offet titlepeut venir avant ce code:

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

Beaucoup d'autres réponses sont exagérées si vous n'avez pas à vous soucier de ce qui suit:

  • Paramètres
  • Répertoire de travail ( cd %~dp0passe au répertoire contenant le fichier de commandes)
Fluorescent Vert5
la source
3
@echo off 
Net session >nul 2>&1 || (PowerShell start -verb runas '%~0' &exit /b)
Echo Administrative privileges have been got. & pause

Ce qui précède fonctionne sur mon Windows 10 version 1903

Matthew Wai
la source
1

Comme j'ai des problèmes avec ce script qui affiche une nouvelle invite de commande avec elle-même à nouveau, en boucle infinie (en utilisant Win 7 Pro), je vous suggère d'essayer une autre approche: Comment puis-je élever automatiquement mon fichier de commandes, afin qu'il demande à Droits d'administrateur UAC si nécessaire?

Attention, vous devez ajouter ceci à la fin du script, comme indiqué dans une modification, afin que vous soyez de retour dans le répertoire du script après l'élévation des privilèges: cd / d% ~ dp0

barbara.post
la source
Vérifiez ma réponse à cette question. Il gère tous ces problèmes.
cyberponk
1

Sur la base de l'article de toster-cx et d'autres articles intéressants sur cette page, j'ai eu un aperçu de la configuration et de la résolution de mon problème. J'ai eu un problème similaire où je souhaitais que l'utilitaire de nettoyage de disque s'exécute chaque semaine deux fois le lundi et le jeudi pendant les heures du déjeuner (par exemple, 14 heures). Cependant, cela exigeait des droits élevés.

Partager un fichier batch qui pourrait aider d'autres débutants comme moi -

@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

Merci beaucoup pour ce forum et Rems POST ici [ https://www.petri.com/forums/forum/windows-scripting/general-scripting/32313-schtasks-exe-need-to-pass-parameters-to-script ][1]

Son message a aidé à configurer l'argument facultatif lors de la planification de la tâche.

Anand
la source
1

Il y a aussi la requête FSUTIL de cet article qui est également liée à ss64.com qui a le code suivant:

@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

Tant que FSUTIL est là, c'est une alternative fiable.

Laurie Stearn
la source
0

Vous ne pouvez pas demander les droits d'administrateur à partir d'un fichier de commandes, mais vous pouvez écrire un script hôte de script Windows dans% temp% et l'exécuter (et qui à son tour exécute votre lot en tant qu'administrateur). Vous voulez appeler la méthode ShellExecute dans le Shell. Objet d'application avec "runas" comme verbe

Anders
la source
0

Utilisez mshtapour demander les droits d'administrateur:

@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

Ou, en utilisant PowerShell:

powershell -c Start-Process "%~nx0" -Verb runas
HackingAddict1337
la source
0

J'ai utilisé plusieurs exemples pour patcher cette doublure fonctionnant ensemble.

Cela ouvrira votre script batch en tant que ADMIN + Maximized Window

Ajoutez simplement l'un des codes suivants en haut de votre script batch. Les deux méthodes fonctionnent, juste différentes façons de le coder.

Je pense que le premier exemple répond le plus rapidement en raison de la /ddésactivation de mes commandes doskey que j'ai activées.

EXAMPLE ONE

@ECHO OFF
IF NOT "%1"=="MAX" (powershell -WindowStyle Hidden -NoProfile -Command {Start-Process CMD -ArgumentList '/D,/C' -Verb RunAs} & START /MAX CMD /D /C %0 MAX & EXIT /B)
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------

:: Your original batch code here:

:--------------------------------------------------------------------------------------------------------------------------------------------------------------------

EXAMPLE TWO

@ECHO OFF
IF NOT "%1"=="MAX" (powershell -WindowStyle Hidden -NoProfile -Command "Start-Process CMD -ArgumentList '/C' -Verb RunAs" & START /MAX CMD /C "%0" MAX & EXIT /B)
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------

:: Your original batch code here:

:--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Voir ci-dessous pour des recommandations sur l'utilisation de votre code de lot d'origine

Placez le code de lot d'origine in it's entirety

Juste parce que la première ligne de code tout en haut a @ECHO OFF n'est pas que vous ne devez pas l'inclure à nouveau si votre script d'origine l'a également.

Cela garantit que lorsque le script est redémarré dans une nouvelle fenêtre s'exécutant maintenant en mode administrateur, vous ne perdez pas vos paramètres / attributs de script prévus ... tels que le répertoire de travail actuel, vos variables locales, etc.

Vous pouvez commencer par les commandes suivantes pour éviter certains de ces problèmes

:: Make sure to use @ECHO OFF if your original code had it
@ECHO OFF
:: Avoid clashing with other active windows variables with SETLOCAL
SETLOCAL
:: Nice color to work with using 0A
COLOR 0A
:: Give your script a name
TITLE NAME IT!

:: Ensure your working directory is set where you want it to be
:: the following code sets the working directory to the script directory folder
PUSHD "%~dp0"

THE REST OF YOUR SCRIPT HERE...

:: Signal the script is finished in the title bar
ECHO.
TITLE Done! NAME IT!
PAUSE
EXIT
slyfox1186
la source
-6

utilisez la commande runas. Mais, je ne pense pas que vous puissiez envoyer un fichier .bat facilement.

Josh
la source
7
Cette réponse est incorrecte. La runascommande ne peut pas être utilisée pour provoquer une élévation.
Bill_Stewart