Elevación automática de UAC
Al intentar realizar con un archivo por lotes tareas que requieren permisos de administrador, como cambiar la configuración del sistema u operar servicios, ¿se ha encontrado alguna vez con el error «Acceso denegado»? Normalmente es necesario hacer clic con el botón derecho en el archivo por lotes y elegir «Ejecutar como administrador». Sin embargo, pedirle al usuario que haga esa operación cada vez resulta engorroso.
En este artículo se explica cómo hacer que el propio archivo por lotes compruebe automáticamente si se está ejecutando con permisos de administrador y, si no los tiene, muestre el cuadro de diálogo de UAC (Control de cuentas de usuario) para elevarse automáticamente.
Comprobar si se ejecuta con permisos de administrador
Para implementar la elevación automática, primero es necesario determinar si «el proceso actual se está ejecutando con permisos de administrador». Para ello, lo habitual es usar el comando net session.
net session es un comando al que se le deniega el acceso si no hay permisos de administrador. Se ejecuta descartando la salida y el resultado se evalúa con ERRORLEVEL.
net session >nul 2>&1
| Situación | ERRORLEVEL |
|---|---|
| Con permisos de administrador | 0 |
| Sin permisos de administrador | Distinto de 0 (normalmente 2) |
net session >nul 2>&1
if %errorlevel% equ 0 (
echo Se está ejecutando con permisos de administrador.
) else (
echo No se tienen permisos de administrador.
)
net session es un comando que muestra información de las sesiones de red, pero aquí se aprovecha su característica de que no se puede ejecutar sin permisos de administrador para comprobar los permisos. Es una técnica sencilla y muy utilizada.
net session depende del servicio Servidor (LanmanServer). Si este servicio está detenido, se produce un error incluso con permisos de administrador y se interpreta erróneamente como falta de permisos. En ese caso se puede usar fltmc >nul 2>&1 como alternativa. fltmc también produce un error si no hay permisos de administrador y no depende del servicio Servidor.
Elevación automática de UAC con PowerShell
Cuando se determina que no hay permisos de administrador, se usa el cmdlet Start-Process de PowerShell para reiniciar el propio archivo por lotes con permisos de administrador.
Patrón básico
@echo off
net session >nul 2>&1
if %errorlevel% neq 0 (
powershell -Command "Start-Process '%~f0' -Verb RunAs"
exit /b
)
rem A partir de aquí se ejecuta el procesamiento con permisos de administrador
cd /d "%~dp0"
echo Ejecutando con permisos de administrador.
pause
Se resume la función de cada parte.
| Instrucción | Descripción |
|---|---|
net session >nul 2>&1 | Comprueba si hay permisos de administrador |
if %errorlevel% neq 0 | Ejecuta la elevación si no hay permisos |
Start-Process '%~f0' | Inicia este mismo archivo por lotes usando su ruta completa |
-Verb RunAs | Ejecuta como administrador (muestra el cuadro de diálogo de UAC) |
exit /b | Finaliza el proceso original (sin permisos) |
cd /d "%~dp0" | Devuelve el directorio actual a la ubicación del archivo por lotes |
%~f0 es una variable especial que representa «la ruta completa de este mismo archivo por lotes». Si el archivo por lotes está en C:\tools\setup.cmd, se expande a C:\tools\setup.cmd. Gracias a esto, el archivo puede reiniciarse correctamente a sí mismo sin importar dónde esté ubicado.
Se resume el flujo de funcionamiento.
- Se comprueban los permisos de administrador con
net session - Si no hay permisos, el archivo se inicia a sí mismo como administrador a través de PowerShell
- Se muestra el cuadro de diálogo de UAC y, cuando el usuario pulsa «Sí», se abre una nueva ventana
- La ventana original se cierra con
exit /b - Como la nueva ventana tiene permisos de administrador, se ejecuta el resto del procesamiento
Lo habitual es que el proceso elevado se inicie con C:\Windows\System32 como directorio actual, en lugar de la ubicación original. Si se hace referencia con rutas relativas a archivos de la misma carpeta que el archivo por lotes, desplácese tras la elevación con cd /d "%~dp0" (%~dp0 es la carpeta donde se encuentra el archivo por lotes).
Conservar los argumentos al elevar
Si se usa el archivo por lotes pasándole argumentos, estos se pierden al elevar tal cual. Transfiera los argumentos originales con la opción -ArgumentList.
@echo off
net session >nul 2>&1
if %errorlevel% neq 0 (
powershell -Command "Start-Process '%~f0' -ArgumentList '%*' -Verb RunAs"
exit /b
)
rem Procesamiento que usa los argumentos
cd /d "%~dp0"
echo Ejecutando con permisos de administrador.
echo Argumentos: %*
pause
%* expande todos los argumentos pasados al archivo por lotes. Por ejemplo, si se ejecuta setup.cmd install verbose, %* será install verbose.
-ArgumentList '%*' pasa los argumentos como una sola cadena, tal como se escribieron. Por eso, si los argumentos contienen comillas simples ('), la sintaxis del lado de PowerShell se rompe. Si contienen comillas dobles (") o &, |, ^, el powershell -Command "..." externo se rompe en la etapa de cmd. Lo mismo ocurre si la ruta de %~f0 contiene estos caracteres. Además, al ejecutarlo sin argumentos, -ArgumentList queda como cadena vacía y Start-Process puede fallar. Si necesita manejar este tipo de entradas, considere migrar a un script de PowerShell.
Ejemplo práctico: cambiar el tipo de inicio de un servicio
Cambiar la configuración de los servicios de Windows requiere permisos de administrador. A continuación se muestra un ejemplo práctico que combina el mecanismo de elevación automática.
@echo off
setlocal
rem Comprobación de elevación automática de UAC
net session >nul 2>&1
if %errorlevel% neq 0 (
echo Se requieren permisos de administrador. Se mostrará el cuadro de diálogo de UAC...
timeout /t 2 >nul
powershell -Command "Start-Process '%~f0' -ArgumentList '%*' -Verb RunAs"
exit /b
)
rem A partir de aquí se ejecuta el procesamiento con permisos de administrador
cd /d "%~dp0"
set SERVICE_NAME=%1
if "%SERVICE_NAME%"=="" set SERVICE_NAME=wuauserv
echo ================================
echo Herramienta de administración de servicios (administrador)
echo ================================
echo Servicio de destino: %SERVICE_NAME%
echo.
sc query %SERVICE_NAME% | findstr /i "STATE"
echo.
echo Se cambiará el servicio a inicio manual...
sc config %SERVICE_NAME% start= demand
if %errorlevel% equ 0 (
echo Se cambió la configuración.
) else (
echo Se produjo un error. Compruebe el nombre del servicio.
)
echo.
pause
endlocal
Al intercalar timeout /t 2 >nul antes de la elevación, el usuario tiene tiempo de leer el mensaje «Se requieren permisos de administrador». Como el cuadro de diálogo de UAC puede sorprender si aparece de repente, es recomendable añadir una breve explicación.
Puntos a tener en cuenta
El cuadro de diálogo de elevación de UAC siempre requiere la confirmación del usuario (hacer clic en el botón «Sí»). No es posible omitir el cuadro de diálogo automáticamente desde un script. Si el usuario pulsa «No», no se realiza la elevación y el procesamiento termina.
En entornos donde UAC está deshabilitado mediante directivas de grupo o donde se controla el comportamiento de la elevación, es posible que este script no funcione como se espera. Además, en entornos con UAC deshabilitado, los usuarios del grupo de administradores siempre se ejecutan ya elevados, por lo que no se muestra el cuadro de diálogo de elevación (net session también se ejecuta correctamente).
Un archivo por lotes que se ejecuta con permisos de administrador puede modificar configuraciones y archivos importantes del sistema. Si un archivo por lotes obtenido de una fuente no confiable incorpora un mecanismo de elevación automática, revise cuidadosamente su contenido antes de ejecutarlo.
Resumen
| Elemento | Contenido |
|---|---|
| Comprobar permisos de administrador | net session >nul 2>&1 |
| Determinar si hay que elevar | if %errorlevel% neq 0 |
| Ejecutar la elevación de UAC | powershell -Command "Start-Process '%~f0' -Verb RunAs" |
| Transferir los argumentos | Añadir -ArgumentList '%*' |
| Finalizar el proceso original | Cerrar la ventana original tras elevar con exit /b |