Saltar al contenido

¿Cómo puedo elevar automáticamente mi archivo por lotes para que solicite derechos de administrador de UAC si es necesario?

Nuestro grupo de redactores ha pasado mucho tiempo investigando respuestas a tus interrogantes, te dejamos la respuestas por eso deseamos serte de mucha ayuda.

Solución:

Existe una forma sencilla sin la necesidad de utilizar 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 se necesita elevación; en ese caso, el script simplemente continúa).

Mira este código (me inspiré en el código de NIronwolf publicado en el hilo Archivo por lotes: ¿”Acceso denegado” en Windows 7?), pero lo he mejorado, en mi versión no hay ningún directorio creado y eliminado para verificar los 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 guión aprovecha el hecho de que NET FILE requiere privilegios de administrador y devoluciones errorlevel 1 si no lo tienes. La elevación se logra creando un script que vuelve a lanzar el archivo por lotes para obtener privilegios. Esto hace que Windows presente el cuadro de diálogo UAC y le solicite 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 (asumiendo que mypackage.msi es un paquete de instalación de servicios) :

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 administrador y contraseña; ahora se le pedirá solo una vez al principio, y solo si es necesario.


Si su secuencia de comandos solo necesita mostrar un mensaje de error y salir si no hay privilegios de administrador en lugar de autoelevación, esto es aún más simple: puede lograr esto agregando lo siguiente al comienzo de su secuencia de comandos:

@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 tiene que hacer clic derecho y seleccionar “Ejecutar como administrador”. La secuencia de comandos continuará después de la REM declaración si detecta derechos de administrador; de lo contrario, salga con un error. Si no necesita el PAUSE, solo quítalo.
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ó a un 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 que 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 agregué un parámetro adicional que se agrega cuando el script se reinicia con derechos elevados.

Las comillas dobles se eliminan por lo siguiente (los detalles están aquí):

setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion

Luego puede acceder a la ruta usando !batchPath!. No contiene comillas dobles, por lo que es seguro decirlo "!batchPath!" más adelante en el guión.

La línea

if '%1'=='ELEV' (shift & goto gotPrivileges)

comprueba si la secuencia de comandos ya ha sido llamada por la secuencia de comandos VBScript para elevar los derechos, evitando así recurrencias interminables. Elimina el parámetro usando shift.


Actualizar:

  • Para evitar tener que registrar el .vbs extensión en Windows 10, He reemplazado la línea
    "%temp%OEgetPrivileges.vbs"
    por
    "%SystemRoot%System32WScript.exe" "%temp%OEgetPrivileges.vbs"
    en el guión de arriba; también agregado cd /d %~dp0 como lo sugirió Stephen (respuesta separada) y 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.

  • De acuerdo con la sugerencia de Artjom B., lo analicé y reemplacé SHIFT por SHIFT /1, que conserva el nombre de archivo de la %0 parámetro

  • Adicional del "%temp%OEgetPrivileges_%batchName%.vbs" al :gotPrivileges sección para limpiar (como mlt sugirió). Adicional %batchName% para evitar el impacto si ejecuta diferentes lotes en paralelo. Tenga en cuenta que necesita usar for para poder aprovechar las ventajas string funciones, como %%~nk, que extrae solo el nombre del archivo.

  • Estructura de script optimizada, mejoras (variable agregada vbsGetPrivileges que ahora se hace referencia en todas partes, lo que permite cambiar la ruta o el nombre del archivo fácilmente, solo eliminar .vbs archivo si es necesario elevar el lote)

  • En algunos casos, se requirió 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

    O cambie el primer parámetro a set cmdInvoke=1 y compruebe si eso ya soluciona el problema. Se agregará cmd.exe al guión 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 de 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 entre comillas dobles, p. Ej. "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:

  • Significado de los caracteres especiales en el archivo por lotes:
    Citas (“), Bang (!), Caret (^), Ampersand (&), Otros caracteres especiales

Como mencionaron jcoder y Matt, PowerShell lo hizo fácil e incluso podría integrarse en el script por lotes sin crear un nuevo script.

Modifiqué el guión de Matt:

:: Check privileges 
net file 1>NUL 2>NUL
if not '%errorlevel%' == '0' (
    powershell Start-Process -FilePath "%0" -ArgumentList "%cd%" -verb runas >NUL 2>&1
    exit /b
)

:: Change directory with passed argument. Processes started with
:: "runas" start with forced C:WindowsSystem32 workdir
cd /d %1

:: Actual work

Lo hago de esta manera:

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 esta manera es simple y usa solo los comandos predeterminados de Windows. Es genial si necesita redistribuir su archivo por lotes.

CD /d %~dp0 Establece el directorio actual en el directorio actual del archivo (si aún no lo está, independientemente de la unidad en la que se encuentre el archivo, gracias a la /d opción).

%~nx0 Devuelve el nombre de archivo actual con extensión (si no incluye la extensión y hay un exe con el mismo nombre en la carpeta, llamará al exe).

Hay tantas respuestas en esta publicación que ni siquiera sé si se verá mi respuesta.

De todos modos, encuentro esta forma más simple que las otras soluciones propuestas en las otras respuestas, espero que ayude a alguien.

Acuérdate de que puedes permitirte añadir un criterio verdadero si diste con el resultado.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *