Quer executar um script PowerShell como administrador e garantir que ele rode dentro da sessão elevada? Este guia mostra a causa do erro clássico “abre a janela, mas o script não roda”, explica o papel das aspas, e entrega modelos prontos para uso local e em larga escala.
Visão geral
Em ambientes Windows, é comum precisar rodar um .ps1
com privilégios administrativos para instalar software, ajustar chaves de registro, ou modificar serviços. Muitos profissionais tentam “Abrir como administrador” e, ao passar o caminho do script, veem apenas a janela elevada do PowerShell se abrir — sem o script ser executado. A causa mais frequente é simples: aspas incorretas no argumento que indica o caminho do script.
Neste artigo você aprenderá:
- Por que o Windows só reconhece aspas duplas como delimitadoras de argumentos ao iniciar processos.
- Como usar
Start-Process -Verb RunAs
para elevar e rodar o script dentro da sessão elevada. - Como definir a ExecutionPolicy de forma segura e pontual.
- Como esperar o término e capturar o exit code.
- Alternativas sem interação de UAC via Tarefa Agendada para distribuição em massa.
- Um checklist de solução de problemas, exemplos práticos e boas práticas para ambientes corporativos.
O problema: aspas que “engolem” o script
No Windows, o delimitador de argumentos reconhecido na criação de processos é a aspa dupla ("
). Já a aspa simples ('
) é interpretada como caractere literal. Se você envia 'C:\temp\MyScript.ps1'
como argumento para powershell.exe -File
, essas aspas simples vão chegar ao executável como parte do texto, e o PowerShell não encontrará o arquivo. Resultado: a janela abre elevada, mas seu script não é carregado.
Solução confirmada (modelo pronto)
Use Start-Process
com -Verb RunAs
e monte os argumentos corretamente. Prefira passar um array de argumentos para evitar problemas de “dupla citação”.
# Caminho do script
$script = 'C:\temp\MyScript.ps1'
Argumentos para a nova instância elevada do PowerShell
\$args = @(
'-NoProfile',
'-ExecutionPolicy', 'RemoteSigned', # ou 'Bypass' se necessário e confiável
'-File', ('"{0}"' -f \$script) # mantém ASPAS DUPLAS no caminho
)
Start-Process -FilePath 'powershell.exe' -Verb RunAs -ArgumentList \$args </code></pre>
<blockquote>
<p><strong>Versão compacta (mesmo efeito)</strong></p>
<pre><code class="language-powershell">Start-Process powershell.exe -Verb RunAs -ArgumentList `
'-NoProfile -ExecutionPolicy RemoteSigned -File "C:\temp\MyScript.ps1"'
</code></pre>
<p>O autor do cenário confirmou: <strong>trocar para aspas duplas</strong> no caminho do script resolveu imediatamente.</p>
</blockquote>
<h2>Por que as aspas importam tanto</h2>
<p>Quando você inicia <code>powershell.exe</code> (ou <code>pwsh.exe</code> no PowerShell 7+), a linha de comando é parseada pelo mecanismo padrão do Windows. Ele <strong>remove</strong> as aspas duplas usadas para delimitar cada argumento e trata aspas simples como <em>texto</em>. Então:</p>
<table>
<thead>
<tr>
<th>Situação</th>
<th>Exemplo</th>
<th>Efeito</th>
</tr>
</thead>
<tbody>
<tr>
<td>Caminho com espaços usando aspas <em>duplas</em> (correto)</td>
<td><code>-File "C:\temp\Meu Script.ps1"</code></td>
<td>Arquivo encontrado e executado</td>
</tr>
<tr>
<td>Caminho com aspas <em>simples</em> (incorreto)</td>
<td><code>-File 'C:\temp\Meu Script.ps1'</code></td>
<td>As aspas simples viram parte do texto; o arquivo não é localizado</td>
</tr>
<tr>
<td>Sem aspas (caminho sem espaços)</td>
<td><code>-File C:\temp\MyScript.ps1</code></td>
<td>Funciona, mas não é resiliente; quebre se houver espaço</td>
</tr>
</tbody>
</table>
<h2>Boas práticas ao montar <code>-ArgumentList</code></h2>
<ul>
<li><strong>Prefira array</strong> em vez de uma única string. Cada elemento vira um argumento isolado:
<pre><code class="language-powershell">$args = @('-NoProfile','-ExecutionPolicy','RemoteSigned','-File','"C:\temp\My Script.ps1"')
Start-Process powershell.exe -Verb RunAs -ArgumentList $args
Se optar por string única, você mesmo deve cuidar de todas as aspas duplas internas:
Start-Process powershell.exe -Verb RunAs -ArgumentList `
'-NoProfile -ExecutionPolicy RemoteSigned -File "C:\temp\My Script.ps1"'
Inclua sempre -NoProfile
para eliminar interferência de perfis.
Especifique -ExecutionPolicy
apenas para a sessão chamada (não altera a máquina).
Política de execução: segura e sob controle
Em clientes Windows, a política padrão geralmente é restritiva (Restricted
), bloqueando scripts por padrão. Opções práticas:
RemoteSigned
: permite scripts locais; exige assinatura para arquivos marcados como “da Internet”.Bypass
: ignora verificações nessa execução específica (use apenas quando a origem for confiável).
Se o script veio por download, remova a marca de Internet antes de executar:
Unblock-File 'C:\temp\MyScript.ps1'
Aguardando término e obtendo o código de saída
Para orquestração e automação, saber se deu certo é tão importante quanto executar:
$p = Start-Process powershell.exe -Verb RunAs -ArgumentList $args -PassThru -Wait
$p.ExitCode
Executando sem janela (quando apropriado)
Para tarefas em segundo plano sem exibir UI:
Start-Process powershell.exe -Verb RunAs -ArgumentList $args -WindowStyle Hidden
Atenção: ocultar a janela pode dificultar suporte e auditoria. Use com critério.
Execução sem interação/UAC: Tarefa Agendada
Para “push” remoto ou execução em escala, a forma mais previsível é criar uma Tarefa Agendada com “Executar com privilégios mais altos” (utilizando conta administrativa ou SYSTEM
), acionar e remover depois:
$act = New-ScheduledTaskAction -Execute 'powershell.exe' `
-Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\temp\MyScript.ps1"'
$prn = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -RunLevel Highest
$trg = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1)
Register-ScheduledTask -TaskName 'RunMyScript' -Action \$act -Trigger \$trg -Principal \$prn
Start-ScheduledTask -TaskName 'RunMyScript'
Opcional: aguarde e então remova a tarefa
Unregister-ScheduledTask -TaskName 'RunMyScript' -Confirm:\$false
Compatibilidade: Windows PowerShell 5.1 vs PowerShell 7+
Nos exemplos usamos powershell.exe
(Windows PowerShell 5.1). Se seu padrão for PowerShell 7+, substitua por pwsh.exe
:
Start-Process 'pwsh.exe' -Verb RunAs -ArgumentList @(
'-NoProfile','-ExecutionPolicy','RemoteSigned','-File','"C:\temp\MyScript.ps1"'
)
Exemplos práticos
Elevar e executar passando parâmetros ao script
$script = 'C:\temp\MyScript.ps1'
$param1 = 'valor simples'
$param2 = 'texto com espaços'
\$args = @(
'-NoProfile',
'-ExecutionPolicy','RemoteSigned',
'-File', ('"{0}"' -f \$script),
'-Name', \$param1,
'-Description', ('"{0}"' -f \$param2)
)
Start-Process powershell.exe -Verb RunAs -ArgumentList \$args
Autoelevação: o script se relança como administrador
Útil quando o usuário dispara o .ps1
sem ter aberto o PowerShell elevado:
# No início do seu script:
$IsAdmin = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent() `
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not \$IsAdmin) {
Write-Host 'Reiniciando como administrador...'
\$quoted = ('"{0}"' -f \$PSCommandPath)
Start-Process powershell.exe -Verb RunAs -ArgumentList @(
'-NoProfile','-ExecutionPolicy','Bypass','-File', \$quoted
)
exit
}
...código elevado continua aqui...
Definindo diretório de trabalho
Alguns scripts assumem diretório específico. Ajuste com -WorkingDirectory
:
Start-Process powershell.exe -Verb RunAs -ArgumentList $args -WorkingDirectory 'C:\temp'
Tabela de opções úteis
Argumentos de powershell.exe
/pwsh.exe
Argumento | Uso | Observação |
---|---|---|
-NoProfile | Ignora perfis | Evita comportamento imprevisível de perfil |
-ExecutionPolicy <Policy> | Define política da sessão | Bypass , RemoteSigned , etc. |
-File "C:\path\script.ps1" | Executa arquivo | Use aspas duplas no caminho |
-Command "<comando>" | Executa comando | Útil para invocações rápidas |
Parâmetros de Start-Process
Parâmetro | Para que serve | Dicas |
---|---|---|
-FilePath | Executável alvo | powershell.exe ou pwsh.exe |
-Verb RunAs | Eleva via UAC | Exige consentimento ou credenciais |
-ArgumentList | Argumentos do processo | Prefira array; cuide das aspas |
-PassThru | Retorna objeto de processo | Combine com -Wait para exit code |
-WindowStyle Hidden | Oculta janela | Use com parcimônia |
-WorkingDirectory | Define diretório | Evita path relativo incorreto |
Distribuição em massa: padrões confiáveis
Ao distribuir para dezenas ou milhares de máquinas (SCCM/MECM, Intune, scripts de logon, etc.), siga estes princípios:
- Empacote dependências no mesmo diretório ou use caminhos absolutos.
- Desbloqueie os arquivos (remova a marca “da Internet”).
- Evite perfis e dependências de usuário (
-NoProfile
). - Capture logs (ex.: redirecione
Start-Transcript
ou write-out para arquivo). - Trate proxy e rede se o script baixar algo.
- Escolha a técnica de elevação adequada:
- RunAs interativo: bom para uso assistido.
- Tarefa Agendada com “Maior nível de privilégios”: ideal para execução sem interação.
- PSRemoting/WinRM: para orquestração remota controlada (exige pré-requisitos).
Erros comuns e como diagnosticar
- Aspas simples no caminho: substitua por aspas duplas e, se possível, passe
-ArgumentList
como array. - ExecutionPolicy bloqueando: defina
-ExecutionPolicy RemoteSigned
ouBypass
apenas na execução. - Arquivo marcado como Internet (Zone.Identifier): rode
Unblock-File
antes. - Diretório de trabalho errado: use
-WorkingDirectory
ou caminhos absolutos. - ESPAÇOS no caminho: sempre envolva em
"aspas duplas"
. - UNC sem permissões: copie para um caminho local com permissões adequadas.
- Herança de ambiente: defina explicitamente variáveis necessárias ou passe parâmetros ao script.
- Linhas muito longas (encadeando comandos): prefira arrays; legibilidade evita erros de citação.
- Executável errado: verifique se usa
powershell.exe
(5.1) oupwsh.exe
(7+). - Sem privilégios apesar de RunAs: confirme com o snippet abaixo e valide política de UAC.
Como confirmar que está realmente elevado
$isAdmin = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent() `
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (\$isAdmin) { 'Elevado' } else { 'Não elevado' }
Perguntas frequentes (FAQ)
Posso usar aspas simples em algum lugar?
Dentro do script PowerShell, sim — para construir strings literais sem interpolação. Mas ao passar caminhos/argumentos para um novo processo no Windows, as aspas que delimitam argumentos precisam ser duplas.
É melhor usar -Command
ou -File
?
Para scripts armazenados em disco, -File
é mais direto (menos camadas de citação). -Command
é útil para pequenos comandos inline.
Preciso mudar a política de execução do sistema?
Na maioria dos casos, não. Prefira passar -ExecutionPolicy
na linha de comando, afetando apenas aquela sessão invocada.
Como capturo saída e logs do script elevado?
Implemente Start-Transcript
no script, redirecione Write-Output
para arquivo, ou use -File
+ parâmetros para apontar um caminho de log.
PowerShell 7 muda algo na citação?
A regra central permanece: aspas duplas delimitam argumentos ao criar o processo; aspas simples são literais. Apenas ajuste o executável alvo para pwsh.exe
.
Modelos prontos para colar
Modelo seguro e verboso
$script = 'C:\temp\MyScript.ps1'
$log = 'C:\temp\MyScript.log'
\$args = @(
'-NoProfile',
'-ExecutionPolicy','RemoteSigned',
'-File', ('"{0}"' -f \$script),
'-LogPath', ('"{0}"' -f \$log)
)
Start-Process powershell.exe -Verb RunAs -ArgumentList \$args -PassThru -Wait |
ForEach-Object { "PID=\$(\$.Id) ExitCode=\$(\$.ExitCode)" }
Modelo compacto “sem janela”
Start-Process powershell.exe -Verb RunAs -ArgumentList `
'-NoProfile -ExecutionPolicy Bypass -File "C:\temp\MyScript.ps1"' `
-WindowStyle Hidden
Modelo de Tarefa Agendada (SYSTEM)
$taskName = 'RunMyScript'
$script = 'C:\temp\MyScript.ps1'
\$act = New-ScheduledTaskAction -Execute 'powershell.exe' \`
-Argument ('-NoProfile -ExecutionPolicy Bypass -File "{0}"' -f \$script)
\$prn = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -RunLevel Highest
\$trg = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1)
Register-ScheduledTask -TaskName \$taskName -Action \$act -Trigger \$trg -Principal \$prn
Start-ScheduledTask -TaskName \$taskName
Tabela de comparação: formas de executar elevado
Técnica | Interação | Cenário ideal | Prós | Contras |
---|---|---|---|---|
Start-Process -Verb RunAs | Requer consentimento/credencial UAC | Admin local na frente da máquina | Simples, nativo | Depende de UAC/usuário |
Tarefa Agendada (Highest/SYSTEM) | Sem interação | Execução em massa e horários programados | Confiável, previsível | Gerência extra (criar/limpar tarefas) |
PSRemoting (WinRM) | Sem interação | Orquestração remota | Escalável, auditável | Requer habilitação e política |
Checklist rápido de troubleshooting
- O caminho do script está entre aspas duplas?
- Você usou
-File
(e não apenas abriu a janela elevada)? - Há marca “da Internet”? Rode
Unblock-File
. - A política de execução da sessão foi definida (
RemoteSigned
ouBypass
)? - Há espaços no caminho? Use
"C:\caminho com espaços\..."
. - Executa como a identidade correta (
RunAs
vsSYSTEM
)? - Precisa de
-WorkingDirectory
para recursos relativos? - Está capturando o exit code com
-PassThru -Wait
?
Resumo e lição principal
Para rodar um script PowerShell com privilégios de administrador e garantir que o script execute dentro da sessão elevada, concentre-se no essencial:
- Elevação:
Start-Process powershell.exe -Verb RunAs
. - Execução do script: passe
-File
e o caminho entre aspas duplas. - Política de execução: ajustada apenas para a chamada (
RemoteSigned
ouBypass
). - Confiabilidade: arrays em
-ArgumentList
,-NoProfile
, e, quando necessário, Tarefa Agendada.
Resumo curto (copiar e colar)
- Use
Start-Process powershell.exe -Verb RunAs
e aspas duplas no caminho do script em-ArgumentList
. - Defina
-ExecutionPolicy
para permitir a execução (RemoteSigned
ouBypass
apenas para a sessão). - Para execução silenciosa e sem prompts em larga escala, prefira uma Tarefa Agendada com privilégios elevados.