Hay una manera fácil sin la necesidad de usar una herramienta externa: funciona bien con Windows 7, 8, 8.1 y 10 y también es compatible con versiones anteriores (Windows XP no tiene ningún UAC, por lo que no es necesaria la elevación). en caso de que el script simplemente continúe).
Echa un vistazo a este código (me inspiró el código de NIronwolf publicado en el hilo Batch File - "Access Denied" en Windows 7? ), Pero lo he mejorado, en mi versión no hay ningún directorio creado y eliminado verificar privilegios de administrador):
::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
:: see "https://stackoverflow.com/a/12264592/1016343" for description
::::::::::::::::::::::::::::::::::::::::::::
@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
El script aprovecha el hecho de que NET FILE
requiere privilegio de administrador y regresa errorlevel 1
si no lo tiene. La elevación se logra mediante la creación de un script que vuelve a iniciar el archivo por lotes para obtener privilegios. Esto hace que Windows presente el cuadro de diálogo UAC y le pide la cuenta de administrador y la contraseña.
Lo he probado con Windows 7, 8, 8.1, 10 y con Windows XP, funciona bien para todos. La ventaja es que, después del punto de inicio, puede colocar cualquier cosa que requiera privilegios de administrador del sistema, por ejemplo, si tiene la intención de reinstalar y volver a ejecutar un servicio de Windows con fines de depuración (se supone que mypackage.msi es un paquete de instalación del servicio) :
msiexec /passive /x mypackage.msi
msiexec /passive /i mypackage.msi
net start myservice
Sin este script de elevación de privilegios, UAC le pediría tres veces su usuario y contraseña de administrador; ahora solo se le pide una vez al principio, y solo si es necesario.
Si su script solo necesita mostrar un mensaje de error y salir si no hay privilegios de administrador en lugar de elevarse automáticamente, esto es aún más simple: puede lograr esto agregando lo siguiente al comienzo de su 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 esta forma, el usuario debe hacer clic derecho y seleccionar "Ejecutar como administrador" . El script continuará después de la REM
declaración si detecta derechos de administrador; de lo contrario, saldrá con un error. Si no necesita el PAUSE
, simplemente quítelo.
Importante: NET FILE [...] EXIT /D)
debe estar en la misma línea. ¡Se muestra aquí en varias líneas para una mejor legibilidad!
En algunas máquinas, he encontrado problemas que ya están resueltos en la nueva versión anterior. Uno se debió al manejo diferente de comillas dobles, y el otro problema se debió al hecho de que UAC estaba deshabilitado (configurado en el nivel más bajo) en una máquina con Windows 7, por lo tanto, el script se llama a sí mismo una y otra vez.
He solucionado esto ahora eliminando las comillas en la ruta y volviéndolas a agregar más tarde, y he agregado un parámetro adicional que se agrega cuando el script se vuelve a iniciar con derechos elevados.
Las comillas dobles se eliminan de la siguiente manera (los detalles están aquí ):
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
Luego puede acceder a la ruta utilizando !batchPath!
. No contiene comillas dobles, por lo que es seguro decirlo "!batchPath!"
más adelante en el script.
La línea
if '%1'=='ELEV' (shift & goto gotPrivileges)
comprueba si el script ya ha sido llamado por el script VBScript para elevar los derechos, evitando así recurrencias infinitas. Elimina el parámetro usando shift
.
Actualizar:
Para evitar tener que registrar la .vbs
extensión en Windows 10 , he sustituido la línea
"%temp%\OEgetPrivileges.vbs"
de
"%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
en el guión anterior; también agregado cd /d %~dp0
según lo sugerido por Stephen (respuesta separada) y por Tomáš Zato (comentario) para establecer el directorio de script como predeterminado.
Ahora el script respeta los parámetros de la línea de comandos que se le pasan. Gracias a jxmallet, TanisDLJ y Peter Mortensen por sus observaciones e inspiraciones.
Según la sugerencia de Artjom B., lo analicé y lo reemplacé SHIFT
por SHIFT /1
, lo que conserva el nombre del archivo para el %0
parámetro
Se agregó del "%temp%\OEgetPrivileges_%batchName%.vbs"
a la :gotPrivileges
sección para limpiar (como se sugiere mlt ). Se agrega %batchName%
para evitar el impacto si ejecuta diferentes lotes en paralelo. Tenga en cuenta que debe usar for
para poder aprovechar las funciones de cadena avanzadas, como por ejemplo %%~nk
, que extrae solo el nombre de archivo.
Estructura de script optimizada, mejoras (variable agregada a la vbsGetPrivileges
que ahora se hace referencia en todas partes que permite cambiar la ruta o el nombre del archivo fácilmente, solo elimine el .vbs
archivo si es necesario elevar el lote)
En algunos casos, se requería una sintaxis de llamada diferente para la elevación. Si el script no funciona, verifique los siguientes parámetros:
set cmdInvoke=0
set winSysFolder=System32
Cambie el primer parámetro a set cmdInvoke=1
y verifique si eso ya soluciona el problema. Se agregará cmd.exe
al script que realiza la elevación.
O intente cambiar el segundo parámetro a winSysFolder=Sysnative
, esto podría ayudar (pero en la mayoría de los casos no es necesario) en sistemas de 64 bits. (ADBailey ha informado esto). "Sysnative" solo es necesario para iniciar aplicaciones de 64 bits desde un host de script de 32 bits (por ejemplo, un proceso de compilación de Visual Studio o invocación de script desde otra aplicación de 32 bits).
Para que quede más claro cómo se interpretan los parámetros, lo estoy mostrando ahora como P1=value1 P2=value2 ... P9=value9
. Esto es especialmente útil si necesita encerrar parámetros como rutas en comillas dobles, por ejemplo "C:\Program Files"
.
Si desea depurar el script VBS, puede agregar el //X
parámetro a WScript.exe como primer parámetro, como se sugiere aquí (se describe para CScript.exe, pero también funciona para WScript.exe).
Enlaces útiles: