Quero que meu arquivo em lotes seja executado apenas elevado. Se não for elevado, forneça uma opção para o usuário reiniciar o lote como elevado.
Estou escrevendo um arquivo em lotes para definir uma variável do sistema, copiar dois arquivos para um local de Arquivos de Programas e iniciar um instalador de driver. Se um usuário do Windows 7 / Windows Vista ( UAC ativado e mesmo se for um administrador local) executá-lo sem clicar com o botão direito do mouse e selecionar "Executar como Administrador", ele receberá 'Acesso Negado' copiando os dois arquivos e escrevendo a variável do sistema .
Eu gostaria de usar um comando para reiniciar automaticamente o lote como elevado se o usuário for de fato um administrador. Caso contrário, se eles não forem um administrador, desejo informar que eles precisam de privilégios de administrador para executar o arquivo em lotes. Estou usando o xcopy para copiar os arquivos e o REG ADD para gravar a variável do sistema. Estou usando esses comandos para lidar com possíveis máquinas Windows XP. Encontrei perguntas semelhantes sobre este tópico, mas nada que lida com o reinício de um arquivo em lotes como elevado.
fonte
@powershell Start-Process cmd -Verb runas
. De Powershell basta cair@powershell
. Isso inicia o cmd com direitos elevados.Respostas:
Você pode fazer com que o script se chame com a opção de psexec
-h
para executar elevado.Não tenho certeza de como você detectaria se ele já está funcionando como elevado ou não ... talvez tente novamente com permissões elevadas apenas se houver um erro de Acesso Negado?
Ou você pode simplesmente ter os comandos para
xcopy
ereg.exe
sempre executarpsexec -h
, mas seria irritante para o usuário final se eles precisassem inserir sua senha a cada vez (ou inseguro se você incluísse a senha no script) ...fonte
psexec -h
não funciona: 'Não foi possível instalar o serviço PSEXESVC: acesso negado.'. Você já precisa ter os direitos de administrador para executar o psexec.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):
O script aproveita o fato de
NET FILE
exigir privilégios de administrador e retornaerrorlevel 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) :
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:
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 precisarPAUSE
, 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 ):
Você pode acessar o caminho usando
!batchPath!
. Ele não contém aspas duplas, por isso é seguro dizer"!batchPath!"
posteriormente no script.A linha
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
porSHIFT /1
, que preserva o nome do arquivo para o%0
parâmetroAdicionado
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 usarfor
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á adicionadocmd.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:
Citações (") , Bang (!) , Caret (^) , E comercial (&) , Outros caracteres especiais
fonte
Como jcoder e Matt mencionaram, o PowerShell facilitou e pode até ser incorporado no script em lote sem criar um novo script.
Eu modifiquei o script de Matt:
fonte
WorkingDirectory
do parâmetro emStart-Process
causa de razões de segurança emrunas
processosEstou usando a excelente resposta de Matt, mas vejo uma diferença entre meus sistemas Windows 7 e Windows 8 ao executar scripts elevados.
Depois que o script é elevado no Windows 8, o diretório atual é definido como
C:\Windows\system32
. Felizmente, existe uma solução fácil, alterando o diretório atual para o caminho do script atual:Nota: Use
cd /d
para garantir que a letra da unidade também seja alterada.Para testar isso, você pode copiar o seguinte em um script. Execute normalmente em qualquer versão para ver o mesmo resultado. Execute como administrador e veja a diferença no Windows 8:
fonte
cd %~dp0
para manter seu caminho atual (presumo que isso funcione também no Win7, portanto o mesmo comando pode ser usado, embora seja necessário apenas para o Win8 +). +1 para isso!pushd %~dp0
vez disso ... por quê? porquepopd
Eu faço assim:
Dessa forma, é simples e use apenas os comandos padrão do Windows. É ótimo se você precisar redistribuir seu arquivo em lote.
CD /d %~dp0
Define o diretório atual como o diretório atual do arquivo (se ainda não estiver, independentemente da unidade em que o arquivo está, graças ao/d
opção).%~nx0
Retorna o nome do arquivo atual com a extensão (se você não incluir a extensão e houver um exe com o mesmo nome na pasta, ele será chamado).Há tantas respostas neste post que eu nem sei se minha resposta será vista.
Enfim, acho isso mais simples do que as outras soluções propostas nas outras respostas, espero que ajude alguém.
fonte
/d
. Obrigado pal :) (PS: Pianista aqui também!)cd
comando para o início (isso garante que o caminho também esteja disponível para o script elevado - caso contrário, o script elevado será executado apenas no system32). Você também deve redirecionar o comando net para nul para ocultar sua saída:net session >nul 2>&1
Matt tem uma ótima resposta, mas retira todos os argumentos passados para o script. Aqui está a minha modificação que mantém argumentos. Também incorporei a correção de Stephen para o problema do diretório de trabalho no Windows 8.
fonte
ECHO UAC.ShellExecute....
linha,"batchArgs!"
não expandirá a variável. Use"!batchArgs!"
. Minha edição foi rejeitada, por isso comento.test.bat "a thing"
ou"test script.bat" arg1 arg2
. Tudo consertado agora.Eu uso o PowerShell para reiniciar o script elevado, se não estiver. Coloque essas linhas no topo do seu script.
Copiei o método 'net name' da resposta de @ Matt. Sua resposta é muito melhor documentada e possui mensagens de erro e coisas do gênero. Este tem a vantagem de o PowerShell já estar instalado e disponível no Windows 7 e superior. Nenhum arquivo temporário VBScript (* .vbs) e você não precisa fazer o download de ferramentas.
Esse método deve funcionar sem qualquer configuração ou instalação, desde que suas permissões de execução do PowerShell não estejam bloqueadas.
fonte
/c %~fnx0 %*'
parte parece deixar todas as partes além da primeira. Por exemplo,test.bat "arg1 arg2 arg3"
somente de arg1 é passado adiantenetsh int set int %wifiname% Enable/Disable
.net file 1>nul 2>nul && goto :run || powershell -ex unrestricted -Command "Start-Process -Verb RunAs -FilePath '%comspec%' -ArgumentList '/c ""%~fnx0""""'"
Para alguns programas, a configuração da
__COMPAT_LAYER
variável de ambiente super secreta comoRunAsInvoker
funcionará. Verifique isto:Embora assim, não haverá UAC solicitando que o usuário continue sem permissões de administrador.
fonte
regedit
. Apenas pulou o uac.Eu colei isso no começo do script:
fonte
cacls
foi preterido no Windows 7 e nas versões mais recentes do Windows.pushd "%CD%"
salva o diretório de trabalho atual e muda para o diretório de trabalho atual?Eu escrevi
gsudo
, umsudo
para Windows : que eleva no console atual (sem alternância de contexto para uma nova janela), com um cache de credenciais (pop-ups de UAC reduzidos) e também eleva os comandos do PowerShell .Ele permite elevar comandos que exigem privilégios de administrador ou todo o lote, se você desejar. Basta colocar
gsudo
antes de qualquer coisa que precise ser elevada.Arquivo em lote de exemplo que se eleva usando gsudo:
EDIT: Nova versão one-liner que funciona com qualquer idioma do Windows e evita problemas de whoami :
Alternativa (versão original):
Instalar:
choco install gsudo
scoop install gsudo
Veja gsudo em ação:
fonte
.Net Framework 4.6
lá. Felizmente,choco install dotnet4.6.2
trouxe algumas dependências difíceis de obter. Em seguida, foigsudo config Prompt "$p# "
corrigido um problema aoConHost
exibir um prompt errado (caracteres de sequência de escape em vez do vermelho acentuado). @RockPaperLizardEmbora não seja diretamente aplicável a essa pergunta, porque deseja algumas informações para o usuário, o google me trouxe aqui quando eu queria executar meu arquivo .bat elevado a partir do agendador de tarefas.
A abordagem mais simples foi criar um atalho para o arquivo .bat, pois, para um atalho, você pode definir
Run as administrator
diretamente nas propriedades avançadas.Executando o atalho do agendador de tarefas, o arquivo .bat é elevado.
fonte
Se você não precisar passar argumentos, aqui está um script compacto de solicitação do UAC com uma única linha. Isso é semelhante ao script de elevação na resposta mais votada, mas não passa argumentos, pois não há uma maneira infalível de fazer isso que lida com todas as combinações possíveis de caracteres suspeitos.
fonte
Usando o PowerShell.
Se o arquivo cmd for longo, eu uso o primeiro para exigir elevação e depois chamo o que está realizando o trabalho.
Se o script for um comando simples, tudo poderá caber em um arquivo cmd. Não esqueça de incluir o caminho nos arquivos de script.
Modelo:
Exemplo 1:
Exemplo 2:
fonte
Tente o seguinte:
Se você precisar de informações sobre esse arquivo em lotes, execute o Snippet HTML / JS / CSS:
fonte
A solução a seguir está limpa e funciona perfeitamente.
Faça o download do arquivo zip Elevate em https://www.winability.com/download/Elevate.zip
Dentro do zip, você deve encontrar dois arquivos: Elevate.exe e Elevate64.exe. (A última é uma compilação nativa de 64 bits, se você precisar que, embora a versão normal de 32 bits, Elevate.exe, deva funcionar bem com as versões de 32 e 64 bits do Windows)
Copie o arquivo Elevate.exe em uma pasta na qual o Windows possa sempre encontrá-lo (como C: / Windows). Ou melhor, você pode copiar na mesma pasta em que planeja manter seu arquivo bat.
Para usá-lo em um arquivo em lotes, basta acrescentar o comando que você deseja executar como administrador ao comando elevate, da seguinte maneira:
fonte