9Sep

Como usar um arquivo em lote para tornar os scripts do PowerShell mais fáceis de executar

Por várias razões, a maioria dos scripts PowerShell relacionados à segurança não são tão facilmente portáveis ​​e utilizáveis ​​quanto os scripts em lote podem ser. No entanto, podemos agrupar um script em lote com nossos scripts do PowerShell para resolver esses problemas. Aqui, mostraremos algumas dessas áreas problemáticas e como criar um script em lote para contorná-las.

Por que não consigo copiar meu arquivo. PS1 para outro computador e executá-lo?

A menos que o sistema de destino tenha sido pré-configurado para permitir a execução de scripts arbitrários, com os privilégios necessários e usando as configurações corretas, é provável que você encontre alguns problemas quando tentar fazer isso.

  1. PowerShell não está associado à extensão de arquivo. PS1 por padrão.
    Nós trouxemos isso inicialmente em nossa série PowerShell Geek School. O Windows associa arquivos. PS1 ao Bloco de Notas por padrão, em vez de enviá-los para o interpretador de comando do PowerShell. Isso é para evitar a execução acidental de scripts maliciosos, basta clicar duas vezes neles. Há maneiras de alterar esse comportamento, mas provavelmente não é algo que você deseja fazer em todos os computadores com os quais você está carregando seus scripts - especialmente se alguns desses computadores não são seus.
  2. PowerShell não permite execução de script externo por padrão.
    A configuração ExecutionPolicy no PowerShell impede a execução de scripts externos por padrão em todas as versões do Windows. Em algumas versões do Windows, o padrão não permite a execução de script. Nós mostramos como alterar essa configuração em Como Permitir a Execução de Scripts do PowerShell no Windows 7. No entanto, isso também é algo que você não quer fazer em qualquer computador.
  3. Alguns scripts do PowerShell não funcionarão sem permissões de administrador.
    Mesmo executando com uma conta de nível de administrador, você ainda precisa passar pelo Controle de Conta de Usuário( UAC) para executar determinadas ações. Não queremos desativar isso, mas ainda é bom quando podemos tornar um pouco mais fácil de lidar.
  4. Alguns usuários podem ter ambientes PowerShell personalizados.
    Você provavelmente não vai se deparar com isso muitas vezes, mas quando você faz isso pode tornar a execução e solução de problemas de scripts um pouco frustrante. Felizmente, podemos contornar isso sem fazer mudanças permanentes também.

Passo 1: clique duas vezes para rodar.

Vamos começar abordando o primeiro problema - associações de arquivos. PS1.Não é possível clicar duas vezes para executar arquivos. PS1, mas você pode executar um arquivo. BAT dessa maneira. Então, vamos escrever um arquivo em lotes para chamar o script do PowerShell da linha de comando para nós.

Portanto, não precisamos reescrever o arquivo em lotes para cada script, ou toda vez que movemos um script ao redor, ele usará uma variável de auto-referência para criar o caminho do arquivo para o script do PowerShell. Para que isso funcione, o arquivo em lotes precisará ser colocado na mesma pasta do seu script do PowerShell e ter o mesmo nome de arquivo. Então, se o seu script do PowerShell é chamado de "MyScript.ps1", você quer nomear seu arquivo em lote "MyScript.bat" e verifique se ele está na mesma pasta. Em seguida, coloque estas linhas no script de lote:

@ECHO OFF PowerShell.exe -Command "& '% ~ dpn0.ps1'" PAUSE

Se não fosse para as outras restrições de segurança no lugar, isso seria realmente tudoÉ preciso executar um script do PowerShell a partir de um arquivo em lotes. De fato, as primeiras e últimas linhas são principalmente apenas uma questão de preferência - é a segunda linha que realmente está fazendo o trabalho. Aqui está a quebra:

@ECHO OFF desliga o comando ecoando. Isso apenas mantém seus outros comandos exibidos na tela quando o arquivo em lote é executado. Esta linha está escondida pelo uso do símbolo at( @) à sua frente.

PowerShell.exe -Command "&'% ~ Dpn0.ps1' "O realmente executa o script do PowerShell. O PowerShell.exe pode, naturalmente, ser chamado a partir de qualquer janela CMD ou arquivo em lote para iniciar o PowerShell em um console simples, como de costume. Você também pode usá-lo para executar comandos diretamente de um arquivo em lotes, incluindo o parâmetro -Command e os argumentos apropriados. A maneira como isso é usado para direcionar nosso arquivo. PS1 é com a variável especial% ~ dpn0.Executar a partir de um arquivo em lotes,% ~ dpn0 avalia a letra da unidade, o caminho da pasta e o nome do arquivo( sem extensão) do arquivo em lotes. Uma vez que o arquivo em lotes e o script do PowerShell estarão na mesma pasta e terão o mesmo nome,% ~ dpn0.ps1 traduzirá para o caminho completo do arquivo do script do PowerShell.

PAUSE apenas faz uma pausa na execução do lote e aguarda a entrada do usuário. Isso geralmente é útil para ter no final de seus arquivos em lote, para que você tenha a chance de rever qualquer comando de saída antes que a janela desapareça.À medida que passamos por testes de cada passo, a utilidade disso se tornará mais óbvia.

Então, o arquivo de lote básico está configurado. Para fins de demonstração, este arquivo é salvo como "D: \ Script Lab \ MyScript.bat" e há um "MyScript.ps1" na mesma pasta. Vamos ver o que acontece quando clicamos duas vezes em MyScript.bat.

Obviamente, o script PowerShell não foi executado, mas é de se esperar - apenas abordamos o primeiro de nossos quatro problemas, afinal. No entanto, existem alguns bits importantes demonstrados aqui:

  1. O título da janela mostra que o script de lote lançou com sucesso o PowerShell.
  2. A primeira linha de saída mostra que um perfil PowerShell personalizado está em uso. Este é o potencial problema # 4, listado acima.
  3. A mensagem de erro demonstra as restrições ExecutionPolicy em vigor. Esse é o nosso problema # 2.
  4. A parte sublinhada da mensagem de erro( que é feita nativamente pela saída de erro do PowerShell) mostra que o script em lote estava segmentando corretamente o script PowerShell pretendido( D: \ Script Lab \ MyScript.ps1).Então, pelo menos, sabemos que tanto está funcionando corretamente.

O perfil, neste caso, é um script simples de uma linha usado para esta demonstração para gerar saída sempre que o perfil está ativo. Você pode personalizar seu próprio perfil do PowerShell para fazer isso também, se você quiser testar esses scripts você mesmo. Basta adicionar a seguinte linha ao seu script de perfil:

Write-Output 'Custom PowerShell profile in effect!'

A ExecutionPolicy no sistema de teste aqui está configurada para RemoteSigned. Isso permite a execução de scripts criados localmente( como o script de perfil), enquanto bloqueiam scripts de fontes externas, a menos que sejam assinados por uma autoridade confiável. Para fins de demonstração, o seguinte comando foi usado para sinalizar MyScript.ps1 como sendo de uma fonte externa:

Add-Content -Path 'D: \ Script Lab \ MyScript.ps1' -Value "[ZoneTransfer]` nZoneId = 3 "-Stream 'Zone. Identifier'

que define o fluxo de dados alternativo Zone. Identifier em MyScript.ps1 para que o Windows pensem que o arquivo veio da Internet. Ele pode ser facilmente revertido com o seguinte comando:

Clear-Content -Path 'D: \ Script Lab \ MyScript.ps1' -Stream 'Zone. Identifier'

Etapa 2: Deslocando ExecutionPolicy.

Como se locomover a configuração ExecutionPolicy, CMD ou um script em lote, é realmente muito fácil. Nós apenas modificamos a segunda linha do script para adicionar mais um parâmetro ao comando PowerShell.exe.

PowerShell.exe -ExecutionPolicy Bypass -Command "& '% ~ dpn0.ps1'"

O parâmetro -ExecutionPolicy pode ser usado para modificar o ExecutionPolicy que é usado quando você cria uma nova sessão do PowerShell. Isso não irá persistir além dessa sessão, para que possamos executar o PowerShell assim sempre que precisarmos, sem enfraquecer a postura de segurança geral do sistema. Agora que corrigimos isso, vamos ter outro objetivo:

Agora que o script foi executado corretamente, podemos ver o que realmente faz. Está nos informando que estamos executando o script como um usuário Limitado. O script está de fato sendo executado por uma conta com permissões de administrador, mas o Controle de Conta de Usuário está ficando no caminho. Embora os detalhes de como o script está verificando o acesso ao Administrador estão além do escopo deste artigo, aqui está o código que está sendo usado para a demonstração:

se( ([Security. Principal. WindowsPrincipal] [Security. Principal. WindowsIdentity]: : GetCurrent() ). IsInRole( [Security. Principal. WindowsBuiltInRole] "Administrador")){ Write-Output 'Running as Administrator!'} Else{ Write-Output 'Running Limited!'} Pausa

Você também notará que há agora doisOperações "Pausa" na saída do script - uma do script do PowerShell e uma do arquivo em lote. A razão para isso será mais evidente no próximo passo.

Passo 3: Obter acesso ao administrador.

Se o seu script não executar comandos que exigem elevação, e você tem certeza de que não terá que se preocupar com os perfis personalizados de ninguém, impedindo o resto. Se você estiver executando alguns cmdlets de nível de administrador, você precisará dessa peça.

Infelizmente, não há como desencadear UAC para elevação dentro de um arquivo em lote ou sessão CMD.No entanto, o PowerShell nos permite fazer isso com o processo de início. Quando usado com "-Verb RunAs" em seus argumentos, Start-Process tentará iniciar um aplicativo com permissões de administrador. Se a sessão PowerShell ainda não estiver elevada, isso irá ativar um prompt do UAC.Para usar isso a partir do arquivo em lotes para iniciar o nosso script, acabaremos gerando dois processos do PowerShell - um para desativar o Processo de Início e outro, iniciado pelo Processo de Início, para executar o script. A segunda linha do arquivo em lotes precisa ser alterada para isso:

PowerShell.exe -Command "&{ Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "-VerbRunAs} "

Quando o arquivo em lote é executado, a primeira linha de saída que veremos é do script de perfil do PowerShell. Então, haverá um prompt UAC quando o processo de início tentar iniciar o MyScript.ps1.

Depois de clicar no prompt do UAC, uma nova instância do PowerShell irá gerar. Uma vez que esta é uma nova instância, é claro, veremos novamente o aviso do script de perfil. Então, MyScript.ps1 corre e vemos que estamos realmente em uma sessão elevada.

E há a razão de ter duas pausas aqui também. Se não fosse no script do PowerShell, nunca veríamos a saída do script - a janela do PowerShell só apareceria e desapareceria assim que o script for executado. E sem a pausa no arquivo em lotes, não poderíamos ver se houve algum erro ao iniciar o PowerShell em primeiro lugar.

Passo 4: deslocando perfis personalizados do PowerShell.

Vamos nos livrar desse desagradável aviso de perfil personalizado agora, devemos? Aqui, dificilmente é um incômodo, mas se o perfil do PowerShell de um usuário muda as configurações, variáveis ​​ou funções padrão de maneiras que você não tenha antecipado com seu script, eles podem ser realmente problemáticos.É muito mais simples executar seu script sem o perfil inteiramente para que você não precise se preocupar com isso. Para fazer isso, precisamos mudar a segunda linha do arquivo em lote mais uma vez:

PowerShell.exe -NoProfile -Command "&{ Processo de início PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File" "% ~ dpn0.ps1 "" '-Verb RunAs} "

Adicionando o parâmetro -NoProfile a ambas as instâncias do PowerShell que são lançadas pelo script significa que o script de perfil do usuário será completamente ignorado em ambas as etapas eo nosso script do PowerShell será executado emum ambiente padrão bastante previsível. Aqui, você pode ver que não há nenhum aviso de perfil personalizado em nenhum dos shells gerados.

Se você não precisa de direitos de administrador no seu script do PowerShell e ignorou a Etapa 3, você pode fazer sem a segunda instância do PowerShell e a segunda linha do seu arquivo de lote deve ser assim:

PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '% ~ dpn0.ps1'"

A saída será assim:

( Claro, para scripts não-Administrador, você pode fazer sem uma pausa de fim de script no seu script do PowerShellneste ponto também, uma vez que tudo é capturado na mesma janela do console e seria mantido lá pela pausa no final do arquivo em lotes de qualquer maneira.)

Arquivos de lote concluídos.

Dependendo se você precisa ou não de permissões de administrador para o seu script do PowerShell( e você realmente não deveria estar solicitando se você não) o arquivo de lote final deve parecer um dos dois abaixo.

Sem acesso de administrador:

@ECHO OFF PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '% ~ dpn0.ps1'" PAUSE

Com acesso de administrador:

@ECHO OFF PowerShell.exe -NoProfile -Command "&{Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""% ~ dpn0.ps1 "" -Verb RunAs} "PAUSE

Lembre-se de colocar o arquivo em lotes na mesma pasta que o script PowerShell que você desejapara usá-lo e dar-lhe o mesmo nome. Então, independentemente do sistema para o qual você tenha esses arquivos, você poderá executar seu script do PowerShell sem precisar se preocupar com nenhuma das configurações de segurança no sistema. Você certamente pode fazer essas mudanças manualmente sempre, mas isso economiza esse problema e você não terá que se preocupar em reverter as mudanças mais tarde.

Referências:

  • Execução de scripts PowerShell a partir de um arquivo em lote - Blog de Programação de Daniel Schroeder
  • Verificando Permissões de Administrador no PowerShell - Hey, Scripting Guy! Blog