Comment puis-je élever automatiquement mon fichier batch, de sorte qu'il demande des droits d'administrateur UAC si nécessaire?
Je veux que mon fichier batch ne s'exécute que surélevé. Si pas élevé, la possibilité pour l'utilisateur de relancer de lot élevé.
J'écris un fichier batch pour définir une variable système, copier deux fichiers dans un emplacement Program Files et démarrer un programme d'installation du pilote. Si un utilisateur Windows 7/Windows Vista (UAC activé et même s'il s'agit d'un administrateur local) l'exécute sans cliquer avec le bouton droit de la souris et sélectionner "Exécuter en tant Qu'administrateur", il obtiendra "Accès refusé" en copiant les deux fichiers et écriture de la variable système.
Je voudrais utiliser une commande pour redémarrer automatiquement le lot élevée si l'utilisateur est en fait un administrateur. Sinon, s'ils ne sont pas un administrateur, je veux leur dire qu'ils ont besoin de privilèges d'administrateur pour exécuter le fichier batch. J'utilise xcopy pour copier les fichiers et REG ADD pour écrire la variable système. J'utilise ces commandes pour faire face à d'éventuelles machines Windows XP. J'ai trouvé des questions similaires sur ce sujet, mais rien qui traite de la relance d'un fichier de lot élevé.
10 réponses
Vous pouvez faire appeler le script lui-même avec l'option psexec -h
pour exécuter elevated.
Je ne suis pas sûr de savoir comment détecter s'il fonctionne déjà comme élevé ou non... peut-être réessayer avec des perms élevés seulement s'il y a une erreur D'Accès refusé?
Ou, vous pourriez simplement avoir les commandes pour le xcopy
et reg.exe
toujours être exécuté avec psexec -h
, mais il serait ennuyeux pour l'utilisateur final s'il a besoin d'entrer son mot de passe à chaque fois (ou non sécurisé si vous avez inclus le mot de passe dans le script)...
Il existe un moyen facile sans avoir besoin d'utiliser un outil externe - il fonctionne bien avec Windows 7, 8, 8.1 et 10 et est également rétrocompatible (Windows XP n'a pas D'UAC, donc l'élévation n'est pas nécessaire-dans ce cas, le script ne fait que commencer).
Consultez ce code (j'ai été inspiré par le code de NIronwolf posté dans le fil fichier Batch- "Accès refusé" sur Windows 7?), mais je l'ai amélioré - dans ma version, il n'y a pas de répertoire créé et supprimé pour vérifier les privilèges d'administrateur):
::::::::::::::::::::::::::::::::::::::::::::
:: 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
Le script profite du fait que NET FILE
nécessite le privilège administrateur et renvoie errorlevel 1
Si vous ne l'avez pas. L'élévation est obtenue en créant un script qui relance le fichier batch pour obtenir des privilèges. Cela fait que Windows présente la boîte de dialogue UAC et vous demande le compte administrateur et le mot de passe.
Je l'ai testé avec Windows 7, 8, 8.1, 10 et avec Windows XP-cela fonctionne très bien pour tout. L'avantage est, après le point de départ, vous pouvez placer tout ce qui nécessite des privilèges d'administrateur système, par exemple, si vous avez l'intention de réinstaller et de relancer un service Windows à des fins de débogage (supposé que mypackage.msi est un package d'installation de service):
msiexec /passive /x mypackage.msi
msiexec /passive /i mypackage.msi
net start myservice
SANS ce script d'élévation de privilèges, UAC vous demanderait trois fois votre utilisateur administrateur et votre mot de passe-maintenant vous n'êtes demandé qu'une seule fois au début, et seulement si nécessaire.
Si votre script a juste besoin d'afficher un message d'erreur et de quitter s'il n'y a pas de privilèges d'administrateur au lieu de auto-élévation, c'est encore plus simple: vous pouvez y parvenir en ajoutant ce qui suit Au début de votre script:
@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 ...
De cette façon, l'utilisateur doit faire un clic droit et sélectionner "Exécuter en tant qu'administrateur". Le script continuera après l'instruction REM
s'il détecte les droits d'administrateur, sinon quittez avec une erreur. Si vous n'avez pas besoin du PAUSE
, supprimez simplement il.
Important: NET FILE [...] EXIT /D)
doit être sur la même ligne. Il est affiché ici en plusieurs lignes pour une meilleure lisibilité!
Sur certaines machines, j'ai rencontré des problèmes, qui sont déjà résolus dans la nouvelle version ci-dessus. L'un était dû à une gestion différente des guillemets doubles, et l'autre problème était dû au fait que L'UAC était désactivé (défini au niveau le plus bas) sur une machine Windows 7, d'où le script s'appelle encore et encore.
J'ai corrigé cela maintenant en dépouillant les citations dans le chemin et les rajouter plus tard, et j'ai ajouté un paramètre supplémentaire qui est ajouté lorsque le script redémarre avec des droits élevés.
Les guillemets doubles sont supprimés par ce qui suit (les détails sont ici):
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
Vous pouvez ensuite accéder au chemin en utilisant !batchPath!
. Il ne contient pas de guillemets doubles, il est donc prudent de dire "!batchPath!"
plus tard dans le script.
La ligne
if '%1'=='ELEV' (shift & goto gotPrivileges)
Vérifie si le script a déjà été appelé par le VBScript script pour élever les droits, évitant ainsi les récursions sans fin. Il supprime le paramètre en utilisant shift
.
Mise à Jour:
Pour éviter d'avoir à s'inscrire à l'
.vbs
extension Windows 10, j'ai remplacé la ligne"%temp%\OEgetPrivileges.vbs"
par"%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
dans le script ci-dessus; également Ajoutécd /d %~dp0
comme suggéré par Stephen (réponse séparée) et par Tomáš Zato (commentaire) pour définir le répertoire de script par défaut.Maintenant, le script honneurs les paramètres de ligne de commande lui sont transmis. Merci à jxmallet, TanisDLJ et Peter Mortensen pour leurs observations et inspirations.
-
Selon l'indice D'Artjom B., Je l'ai analysé et j'ai remplacé
SHIFT
parSHIFT /1
, qui conserve le nom du fichier pour le paramètre%0
Ajouté
del "%temp%\OEgetPrivileges_%batchName%.vbs"
de la:gotPrivileges
section pour nettoyer (comme mlt suggéré). Ajouté%batchName%
pour éviter tout impact si vous exécutez différents lots en parallèle. Notez que vous devez utiliserfor
pour être capable de tirer parti des fonctions de chaîne avancées, telles que%%~nk
, qui extrait uniquement le nom de fichier.-
Structure de script optimisée, améliorations (variable ajoutée
vbsGetPrivileges
qui est maintenant référencée partout permettant de changer facilement le chemin ou le nom du fichier, supprimer uniquement le fichier.vbs
si le lot doit être élevé) Dans certains cas, une syntaxe d'appel différente était requise pour l'élévation. Si le script ne fonctionne pas, vérifiez ce qui suit paramètres:
set cmdInvoke=0
set winSysFolder=System32
Changez le 1er paramètre enset cmdInvoke=1
et vérifiez si cela résout déjà le problème. Il ajouteracmd.exe
au script effectuant l'élévation.
Ou essayez de changer le 2ème paramètre enwinSysFolder=Sysnative
, cela peut aider (mais n'est dans la plupart des cas pas nécessaire) sur les systèmes 64 bits. (ADBailey a signalé cela). "Sysnative" n'est requis que pour le lancement d'applications 64 bits à partir d'un hôte de script 32 bits (par exemple, un processus de construction Visual Studio ou une autre application 32 bits).Pour rendre plus clair comment les paramètres sont interprétés, Je l'affiche maintenant comme
P1=value1 P2=value2 ... P9=value9
. Ceci est particulièrement utile si vous devez entourer des paramètres comme les chemins entre guillemets doubles, par exemple"C:\Program Files"
.
Comme jcoder et Matt l'ont mentionné, PowerShell l'a rendu facile, et il pourrait même être intégré dans le script batch sans créer de nouveau script.
J'ai modifié le script de Matt:
:checkPrivileges
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges
) else ( powershell "saps -filepath %0 -verb runas" >nul 2>&1)
exit /b
Il n'y a pas besoin de l'Étiquette :getPrivileges
.
J'utilise L'excellente réponse de Matt, mais je vois une différence entre mes systèmes Windows 7 et Windows 8 lors de l'exécution de scripts élevés.
Une fois que le script est élevé sur Windows 8, le répertoire courant est défini sur C:\Windows\system32
. Heureusement, il existe une solution de contournement facile en changeant le répertoire courant sur le chemin du script courant:
cd /d %~dp0
Remarque: Utilisez cd /d
pour vous assurer que la lettre de lecteur est également modifiée.
Pour tester cela, vous pouvez copier ce qui suit dans un script. Exécuter normalement sur les deux versions pour voir le même résultat. Exécutez en tant Qu'administrateur et voyez la différence dans 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
Je le fais de cette façon:
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
De cette façon, c'est simple et utilisez uniquement les commandes par défaut de windows. C'est génial si vous avez besoin de redistribuer votre fichier batch.
CD /d %~dp0
définit le répertoire courant sur le répertoire courant du fichier (s'il ne l'est pas déjà, quel que soit le lecteur dans lequel se trouve le fichier, grâce à l'option /d
).
%~nx0
retourne le nom de fichier actuel avec l'extension (Si vous n'incluez pas l'extension et qu'il y a un exe avec le même nom sur le dossier, il appellera EXE).
Il y a tellement de réponses sur ce post que je ne sais même pas si ma réponse sera vue.
Quoi qu'il en soit, je trouve cette façon plus simple que les autres solutions proposées sur les autres réponses, j'espère que cela aide quelqu'un.
Matt a une excellente réponse, mais il supprime tous les arguments passés au script. Voici ma modification qui garde des arguments. J'ai également incorporé le correctif de Stephen pour le problème du répertoire de travail dans 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...
J'utilise PowerShell pour relancer le script élevé si ce n'est pas le cas. Mettre ces lignes tout en haut de votre script.
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
J'ai copié la méthode 'net name' de la réponse de @Matt. Sa réponse est beaucoup mieux documentée et a des messages d'erreur et autres. Celui-ci a l'avantage que PowerShell est déjà installé et disponible sur Windows 7. Pas de VBScript temporaire (*.VBS), et vous n'avez pas besoin de télécharger des outils.
Cette méthode devrait fonctionner sans aucune configuration ou configuration, tant que vos autorisations D'exécution PowerShell ne sont pas verrouillées.
Pour certains programmes, définir la variable d'environnement super secret __COMPAT_LAYER
sur RunAsInvoker
fonctionne .Vérifiez ceci:
set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe
Bien que comme ça, il n'y aura pas D'UAC invitant l'utilisateur à continuer sans autorisations d'administrateur.
J'ai collé ceci au début du script:
:: 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"
:--------------------------------------
La solution suivante est propre et fonctionne parfaitement.
Télécharger Élever fichier zip à partir de https://www.winability.com/download/Elevate.zip
-
Dans zip, vous devriez trouver deux fichiers: Elevate.exe et Elevate64.EXE. (Ce dernier est une compilation 64 bits native, si vous en avez besoin, bien que la version 32 bits régulière, Elevate.exe, devrait fonctionner correctement avec les versions 32 et 64 bits de Windows)
Copiez le fichier Élever.exe dans un dossier où Windows peut toujours le trouver (comme C:/Windows). Ou mieux vous pouvez copier dans le même dossier où vous prévoyez de garder votre fichier bat.
-
Pour l'utiliser dans un fichier batch, ajoutez simplement la commande que vous souhaitez exécuter en tant qu'administrateur avec la commande elevate, comme ceci:
elevate net start service ...