Pagina inicial » como » Como usar um arquivo em lotes para facilitar a execução de scripts do PowerShell

    Como usar um arquivo em lotes para facilitar a execução de scripts do PowerShell

    Por vários motivos, principalmente relacionados à segurança, os scripts do PowerShell não são tão portáteis e fáceis de usar quanto os scripts em lote podem ser. No entanto, podemos agrupar um script em lote com nossos scripts do PowerShell para contornar esses problemas. Aqui, mostraremos algumas dessas áreas problemáticas e como criar um script em lote para contorná-las.

    Por que não posso simplesmente 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ê tenha alguns problemas ao tentar fazer isso..

    1. O 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 ao interpretador de comandos do PowerShell. Isso é para impedir a execução acidental de scripts mal-intencionados simplesmente clicando duas vezes neles. Existem maneiras de você mudar esse comportamento, mas provavelmente não é algo que você queira fazer em todos os computadores em que você carrega seus scripts - especialmente se alguns desses computadores não forem seus..
    2. O PowerShell não permite a execução de scripts externos 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 scripts. Mostramos a você 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 deseja fazer em qualquer computador.
    3. Alguns scripts do PowerShell não funcionam 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ós não queremos desabilitar isso, mas ainda é bom quando podemos tornar um pouco mais fácil lidar com.
    4. Alguns usuários podem ter ambientes personalizados do PowerShell.
      Você provavelmente não encontrará isso com frequência, mas quando isso acontecer, poderá tornar a execução e a solução de problemas de seus scripts um pouco frustrantes. Felizmente, podemos contornar isso sem fazer alterações permanentes também.

    Etapa 1: clique duas vezes para executar.

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

    Portanto, não precisamos reescrever o arquivo em lote para cada script ou, toda vez que movemos um script, ele usa 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 script do PowerShell e ter o mesmo nome de arquivo. Portanto, se o script do PowerShell for chamado de “MyScript.ps1”, você deverá nomear o arquivo de lote “MyScript.bat” e certificar-se de que ele esteja na mesma pasta. Em seguida, coloque essas linhas no script em lote:

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

    Se não fosse pelas outras restrições de segurança em vigor, isso seria realmente o suficiente para executar um script do PowerShell a partir de um arquivo em lotes. Na verdade, 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á o detalhamento:

    @ ECHO OFF desativa o comando ecoando. Isso apenas impede que seus outros comandos sejam exibidos na tela quando o arquivo em lote é executado. Esta linha é escondida pelo uso do símbolo (@) na frente dela.

    PowerShell.exe -Command “& '% ~ dpn0.ps1'” na verdade, executa o script do PowerShell. O PowerShell.exe pode, é claro, ser chamado de qualquer janela CMD ou arquivo em lotes para iniciar o PowerShell em um console simples, como de costume. Você também pode usá-lo para executar comandos diretamente de um arquivo de lote, incluindo o parâmetro -Command e argumentos apropriados. A maneira como isso é usado para direcionar nosso arquivo .PS1 é com a variável especial% ~ dpn0. Executar 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. Como o arquivo em lotes e o script do PowerShell estarão na mesma pasta e terão o mesmo nome,% ~ dpn0.ps1 será convertido no caminho completo do arquivo do script do PowerShell.

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

    Então, o arquivo de lote básico está configurado. Para fins de demonstração, esse 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 do PowerShell não foi executado, mas isso é esperado - afinal, só abordamos o primeiro dos nossos quatro problemas. No entanto, existem alguns pedaços importantes demonstrados aqui:

    1. O título da janela mostra que o script em lote lançou o PowerShell com sucesso.
    2. A primeira linha de saída mostra que um perfil personalizado do PowerShell está em uso. Este é o problema em potencial # 4, listado acima.
    3. A mensagem de erro demonstra as restrições de ExecutionPolicy em vigor. Esse é o nosso problema # 2.
    4. A parte sublinhada da mensagem de erro (que é feita de forma nativa pela saída de erro do PowerShell) mostra que o script em lote estava direcionando corretamente o script do PowerShell pretendido (D: \ Script Lab \ MyScript.ps1). Então, pelo menos sabemos que muito 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 estiver ativo. Você pode personalizar seu próprio perfil do PowerShell para fazer isso também, se quiser testar esses scripts sozinho. Basta adicionar a seguinte linha ao seu script de perfil:

    Perfil Custom PowerShell do Write-Output 'em vigor!'

    A ExecutionPolicy no sistema de teste aqui está definida como RemoteSigned. Isso permite a execução de scripts criados localmente (como o script de perfil), enquanto bloqueia scripts de fontes externas, a menos que eles 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 '

    Isso define o fluxo de dados alternativo do Zone.Identifier em MyScript.ps1 para que o Windows pense que o arquivo veio da Internet. Pode ser facilmente revertido com o seguinte comando:

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

    Etapa 2: contornar a ExecutionPolicy.

    Contornar a configuração de ExecutionPolicy, do CMD ou de um script em lote, é realmente muito fácil. 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 a ExecutionPolicy que é usada quando você gera uma nova sessão do PowerShell. Isso não persistirá além dessa sessão, para que possamos executar o PowerShell desta forma sempre que precisarmos, sem enfraquecer a postura geral de segurança do sistema. Agora que consertamos isso, vamos fazer outra coisa:

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

    if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity] :: GetCurrent ()). IsInRole ([Security.Principal.WindowsBuiltInRole] "Administrador")) Write-Output 'em execução como administrador!' else Write-Output 'Running Limited!' Pausa

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

    Etapa 3: Obtendo acesso de administrador.

    Se o seu script não executar nenhum comando que exija elevação e você tiver certeza de que não precisará se preocupar com o fato de os perfis personalizados de ninguém atrapalharem, ignore o restante disso. Se você estiver executando alguns cmdlets de nível de administrador, precisará dessa peça.

    Infelizmente, não há como acionar o UAC para elevação a partir de um arquivo de lote ou sessão CMD. No entanto, o PowerShell nos permite fazer isso com o Start-Process. Quando usado com “-Verb RunAs” em seus argumentos, o Start-Process tentará iniciar um aplicativo com permissões de Administrador. Se a sessão do PowerShell ainda não estiver elevada, isso acionará um prompt do UAC. Para usar isso a partir do arquivo em lote para iniciar nosso script, acabaremos gerando dois processos do PowerShell - um para disparar o Start-Process e outro, iniciado pelo Start-Process, para executar o script. A segunda linha do arquivo de lote precisa ser alterada para isso:

    PowerShell.exe -Command "& Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "-Verb RunAs"

    Quando o arquivo em lote é executado, a primeira linha de saída que veremos é do script de perfil do PowerShell. Em seguida, haverá um prompt do UAC quando o Start-Process tentar iniciar o MyScript.ps1.

    Depois de clicar no prompt do UAC, uma nova instância do PowerShell será gerada. Como essa é uma nova instância, é claro, veremos novamente o aviso do script de perfil. Então, MyScript.ps1 é executado e vemos que estamos de fato em uma sessão elevada.

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

    Etapa 4: contornar os perfis personalizados do PowerShell.

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

    PowerShell.exe -NoProfile -Command "& Iniciar-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "-Verb RunAs"

    Adicionar o parâmetro -NoProfile às duas instâncias do PowerShell que são iniciadas pelo script significa que o script de perfil do usuário será completamente ignorado nas duas etapas e nosso script do PowerShell será executado em um ambiente padrão razoavelmente previsível. Aqui, você pode ver que não há aviso de perfil personalizado em nenhum dos shells gerados.

    Se você não precisar de direitos de administrador no seu script do PowerShell e tiver pulado a Etapa 3, poderá ficar sem a segunda instância do PowerShell e a segunda linha do arquivo de lote deverá ficar assim:

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

    A saída ficará assim:

    (Obviamente, para scripts que não são de administrador, você também poderia fazer uma pausa no fim do script em seu script do PowerShell, já que tudo é capturado na mesma janela do console e seria mantido ali pela pausa no final de o arquivo de lote de qualquer maneira.)

    Arquivos em lote concluídos.

    Dependendo se você precisa ou não de permissões de administrador para o script do PowerShell (e você realmente não deveria solicitá-las se não tiver), o arquivo de lote final deve se parecer com 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 "& Iniciar-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -Arquivo" "% ~ dpn0.ps1" "-Verb RunAs" PAUSE

    Lembre-se de colocar o arquivo de lote na mesma pasta que o script do PowerShell para o qual deseja usá-lo e nomeie-o. Então, independentemente do sistema para o qual você levar esses arquivos, você poderá executar o script do PowerShell sem ter que se preocupar com as configurações de segurança do sistema. Você certamente poderia fazer essas alterações manualmente todas as vezes, mas isso poupa esse problema e você não terá que se preocupar em reverter as alterações mais tarde.


    Referências:

    • Executando scripts do PowerShell a partir de um arquivo em lotes - Blog de programação de Daniel Schroeder
    • Verificando permissões de administrador no PowerShell - Ei, Equipe de Scripts! Blog