Existe uma maneira fácil, sem a necessidade de usar uma ferramenta externa - ela funciona bem com o Windows 7, 8, 8.1 e 10 e também é compatível com versões anteriores (o Windows XP não possui UAC, portanto, a elevação não é necessária - pois caso o script continue).
Confira este código (fui inspirado pelo código de NIronwolf publicado no tópico Arquivo em Lote - "Acesso Negado" no Windows 7? ), Mas eu o melhorei - na minha versão não há nenhum diretório criado e removido para verifique os privilégios 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
O script aproveita o fato de NET FILE
exigir privilégios de administrador e retorna errorlevel 1
se você não o tiver. A elevação é alcançada através da criação de um script que reinicia o arquivo em lotes para obter privilégios. Isso faz com que o Windows apresente a caixa de diálogo do UAC e solicita a conta e a senha do administrador.
Eu testei com o Windows 7, 8, 8.1, 10 e com o Windows XP - funciona bem para todos. A vantagem é que, após o ponto de início, você pode colocar qualquer coisa que exija privilégios de administrador do sistema, por exemplo, se você pretende reinstalar e executar novamente um serviço do Windows para fins de depuração (assumindo que mypackage.msi é um pacote de instalação do serviço) :
msiexec /passive /x mypackage.msi
msiexec /passive /i mypackage.msi
net start myservice
Sem esse script de elevação de privilégio, o UAC solicitaria três vezes seu usuário e senha de administrador - agora você é solicitado apenas uma vez no início e somente se necessário.
Se o seu script precisar apenas mostrar uma mensagem de erro e sair se não houver privilégios de administrador em vez de elevar automaticamente, isso é ainda mais simples: você pode conseguir isso adicionando o seguinte no início do 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 ...
Dessa forma, o usuário deve clicar com o botão direito do mouse e selecionar "Executar como administrador" . O script continuará após a REM
instrução se detectar direitos de administrador, caso contrário, sairá com um erro. Se você não precisar PAUSE
, basta removê-lo.
Importante: NET FILE [...] EXIT /D)
deve estar na mesma linha. É exibido aqui em várias linhas para melhor legibilidade!
Em algumas máquinas, encontrei problemas que já foram resolvidos na nova versão acima. Um foi devido ao tratamento de aspas duplas diferentes, e o outro problema foi devido ao fato de o UAC ter sido desativado (definido no nível mais baixo) em uma máquina com Windows 7; portanto, o script se autodenomina várias vezes.
Corrigi isso agora removendo as aspas no caminho e adicionando-as novamente mais tarde, e adicionei um parâmetro extra que é adicionado quando o script é reiniciado com direitos elevados.
As aspas duplas são removidas pelo seguinte (detalhes estão aqui ):
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
Você pode acessar o caminho usando !batchPath!
. Ele não contém aspas duplas, por isso é seguro dizer "!batchPath!"
posteriormente no script.
A linha
if '%1'=='ELEV' (shift & goto gotPrivileges)
verifica se o script já foi chamado pelo script VBScript para elevar direitos, evitando recursões sem fim. Ele remove o parâmetro usando shift
.
Atualizar:
Para evitar ter que registrar a .vbs
extensão no Windows 10 , eu ter substituído a linha
"%temp%\OEgetPrivileges.vbs"
por
"%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
no script acima; também adicionado cd /d %~dp0
como sugerido por Stephen (resposta separada) e por Tomáš Zato (comentário) para definir o diretório de scripts como padrão.
Agora, o script honra os parâmetros da linha de comando que estão sendo passados para ele. Obrigado a jxmallet, TanisDLJ e Peter Mortensen pelas observações e inspirações.
De acordo com a dica de Artjom B., analisei e substituí SHIFT
por SHIFT /1
, que preserva o nome do arquivo para o %0
parâmetro
Adicionado del "%temp%\OEgetPrivileges_%batchName%.vbs"
à :gotPrivileges
seção para limpeza (como mlt sugerido). Adicionado %batchName%
para evitar impacto se você executar lotes diferentes em paralelo. Observe que você precisa usar for
para poder tirar proveito das funções avançadas de string, como %%~nk
, que extrai apenas o nome do arquivo.
Estrutura de script otimizada, melhorias (variável adicionada vbsGetPrivileges
que agora é referenciada em todos os lugares, permitindo alterar facilmente o caminho ou o nome do arquivo, exclua o .vbs
arquivo apenas se o lote precisar ser elevado)
Em alguns casos, era necessária uma sintaxe de chamada diferente para elevação. Se o script não funcionar, verifique os seguintes parâmetros:
set cmdInvoke=0
set winSysFolder=System32
Altere o 1º parâmetro para set cmdInvoke=1
e verifique se isso já corrige o problema. Ele será adicionado cmd.exe
ao script que executa a elevação.
Ou tente alterar o segundo parâmetro para winSysFolder=Sysnative
, isso pode ajudar (mas na maioria dos casos não é necessário) em sistemas de 64 bits. (ADBailey relatou isso). "Sysnative" é necessário apenas para iniciar aplicativos de 64 bits a partir de um host de scripts de 32 bits (por exemplo, um processo de criação do Visual Studio ou chamada de script de outro aplicativo de 32 bits).
Para deixar mais claro como os parâmetros são interpretados, eu estou exibindo isso agora P1=value1 P2=value2 ... P9=value9
. Isso é especialmente útil se você precisar incluir parâmetros como caminhos entre aspas duplas, por exemplo "C:\Program Files"
.
Se você quiser depurar o script VBS, poderá adicionar o //X
parâmetro ao WScript.exe como primeiro parâmetro, conforme sugerido aqui (ele é descrito para CScript.exe, mas também funciona para WScript.exe).
Links Úteis: