Quando você escreve um script PowerShell sem funções e sem dependências externas em outros scripts, o conceito dos escopos PowerShell não é de grande preocupação. O conceito das variáveis globais do PowerShell não é front and center. Mas à medida que você começa a construir funções, módulos e aprende a chamar scripts de outros scripts, o tópico torna-se mais importante.
Neste artigo, você vai ter uma profunda lição sobre o que são os escopos no PowerShell, como eles funcionam, e como você pode escrever código com os escopos em mente. Quando você terminar, você entenderá as variáveis globais do PowerShell e muito mais!
Tabela de conteúdos
- Escopos: Tipo Baldes
- Tipos de Escopo
- Escopo Global
- Escopo do script
- Escopo Privado
- Escopo Local
- Escopos de referência
- Nomeados Escopos
- Escopos Numerados
- Hierarquia e herança de escopo
- Definindo e acessando itens nos escopos
- Obter/Definir-Variável
- Escopos Locais
- Escopo Privado/Script/Global
- Escopo “Prefacing”
- Escopos locais
- Escopos privados/escritos/globais
- Escopos em Scriptblocks
- Dot Sourcing Scripts (Troca de Escopos Locais)
- Usando a propriedade AllScope (Option)
- Escopos de funções
- Manter itens privados (Desabilitando a herança)
- Melhores Práticas de Escopo
- Leitura adicional
Escopos: Tipo Baldes
Deixou alguma vez escrever um script onde você define uma variável e quando você verifica o valor dessa variável, é algo mais? Você pode coçar a sua cabeça em como essa variável mudou quando você a definiu claramente. Um motivo pode ser o valor da variável estar sendo sobrescrito em outro escopo.
Talvez você tenha se perguntado como certas variáveis PowerShell têm valores quando você as referencia em seu console, mas não existem em seus scripts. É provável que essas variáveis estejam em outro ‘balde’ que não está disponível naquele momento.
Scopes são como baldes. Os escopos afectam a forma como o PowerShell isola variáveis, pseudónimos, funções e PSDrives entre diferentes áreas. Um escopo é como um balde. É um lugar para coletar todos esses itens juntos.
Quando o PowerShell inicia, ele cria automaticamente esses “baldes” para você. Nesse momento, você já está usando os escopos sem perceber. Todos os escopos são definidos pelo PowerShell e são criados sem qualquer ajuda de sua parte.
Tipos de Escopo
Quando o PowerShell dispara, ele cria automaticamente quatro “baldes” ou escopos para vários itens a serem colocados. Você não pode criar escopos por conta própria. Você só pode adicionar e remover itens desses escopos definidos abaixo.
Escopo Global
Items definidos quando o PowerShell abre são definidos no escopo global. Estes itens incluem objectos criados pelo sistema como unidades PowerShell e também qualquer coisa que tenha definido num perfil PowerShell, uma vez que o seu perfil corre na inicialização.
Itens no escopo global estão disponíveis em qualquer lugar. Pode referenciar itens no âmbito global interactivamente na consola, em qualquer script que execute e em qualquer função. As variáveis globais do PowerShell estão em todo o lado. Por este motivo, o uso comum das variáveis globais do PowerShell é usar variáveis globais do PowerShell entre scripts.
Existe apenas um escopo global que governa globalmente.
Escopo do script
Um escopo do script é criado automaticamente toda vez que um script do PowerShell é executado. Você pode ter muitas instâncias diferentes de escopo de script. Os escopos de script são criados quando você executa um script PS1 ou um módulo, por exemplo.
Apenas os itens criados naquela instância específica do escopo do script podem se referir uns aos outros.
Escopo Privado
Tipicamente, um item definido pode ser acessado de outros escopos – não é verdade com itens em um escopo privado. Itens em um escopo privado, contêm objetos que estão ocultos para outros escopos. Um escopo privado é usado para criar itens com o mesmo nome que itens em outros escopos para evitar sobreposição.
Escopo Local
Não como os outros escopos, o escopo local é um pouco diferente. O escopo local é um ponteiro para o escopo global, script ou privado. O escopo local é relativo a qualquer contexto em que o código roda no momento.
Se você criar uma variável, alias, função ou PSDrive sem atribuir-lhe explicitamente um escopo (que iremos cobrir mais tarde), ele irá para o escopo local.
Escopos de referência
Agora você tenha uma idéia dos quatro tipos de escopos que existem, você também deve saber que existem duas maneiras de referenciar esses escopos.
No PowerShell, existem duas maneiras de referenciar escopos – nomeados ou numerados. Ambos os métodos estão referenciando os mesmos escopos, mas simplesmente de uma maneira diferente. Estes são dois modos diferentes de interagir com os escopos.
Nomeados Escopos
Acima na seção Scope Type, você aprendeu sobre os escopos referenciados pelo nome. Referenciar um escopo pelo nome é, intuitivamente, chamado de escopo nomeado. O principal objetivo de referenciar um escopo pelo nome é atribuir um item a um escopo. Você aprenderá como fazer isso abaixo.
Escopos Numerados
Por um nome, cada escopo tem um número começando em zero, que será sempre o escopo local. Os escopos são numerados dinamicamente em relação ao escopo local atual.
Por exemplo, assim que você abre uma sessão PowerShell, você está operando no escopo global. Neste ponto, o escopo global é o escopo local (lembre-se que o escopo local é apenas um ponteiro).
Desde que o escopo local é sempre o escopo zero, neste ponto, o escopo global também é atualmente o escopo zero. Mas, quando você executa um script a partir dessa mesma sessão, um escopo do script é criado. Ao ser executado, o ponteiro do escopo local é então alterado para o escopo do script. Agora o escopo do script é o escopo zero e o escopo global é o escopo um.
Scopes são numerados Este processo se repete para tantos escopos quantos você tiver onde o escopo local é 0. Os escopos são numerados dinamicamente por hierarquia de escopo.
Hierarquia e herança de escopo
Como mencionado anteriormente, quando você inicia uma sessão PowerShell, PowerShell cria alguns itens para você no escopo global. Esses itens podem ser funções, variáveis, pseudônimos ou PSDrives. Qualquer coisa que você definir na sua sessão PowerShell será definida no escopo global também.
Desde que você esteja no escopo global por padrão, se você fizer algo que cria outro escopo como executar um script ou executar uma função, um escopo filho será criado com o pai sendo o escopo global. Os escopos são como processos com pais e filhos.
Qualquer coisa que esteja definida no escopo dos pais, o escopo global, neste caso, será acessível no escopo filho. Mas estes itens só são editáveis no escopo que foram definidos em.
Vamos dizer que você tem um script chamado Test.ps1. Dentro deste script há uma única linha como mostrado abaixo.
$a = 'Hello world!'
Quando você executa este script, $a
é atribuído um valor no escopo local (script enquanto o script está sendo executado). Quando o Test.ps1 é executado, você pode ver abaixo que você é incapaz de referenciá-lo após a execução do script. Como $a
foi atribuído enquanto no escopo do script, o escopo global (no console interativo) não pode vê-lo.
Vamos dar um passo adiante neste exemplo e fazer com que o script Test.ps1 se pareça com o que está abaixo. O script está agora a tentar sair o valor de $a
antes de defini-lo no mesmo escopo.
Write-Output $a$a = 'Hello world!'
Para demonstrar, atribua um valor para $a
no console interactivo. Isto atribui o valor no escopo global. Agora, o script é executado, ele herdará o escopo pai (global) e deverá ser capaz de ver o valor.
Você pode ver abaixo que quando o Test.ps1 é executado (criando um escopo filho do escopo global), ele pode ver o valor de $a
. Você também pode ver que o valor da variável está disponível no escopo global também, uma vez que este escopo é onde ele foi definido. Isto significa que $a
está disponível tanto no script (child) como no escopo dos pais (global).
Remmbrar este comportamento de herança de escopo. Ao fazer isso, você será ajudado quando houver conflitos na resolução de problemas, tais como variáveis em diferentes escopos com o mesmo nome.
Definindo e acessando itens nos escopos
Agora você sabe o que é um escopo e como eles funcionam, como você os acessa? Vamos ver como usar o PowerShell para definir um escopo de variável (e acessá-los).
Obter/Definir-Variável
No PowerShell, há dois cmdlets que permitem definir variáveis chamadas Get-Variable
e Set-Variable
. Estes cmdlets permitem-lhe recuperar o valor de uma variável ou definir um valor.
Both cmdlets são semelhantes com um parâmetro Name
e Scope
. Usando estes parâmetros, o PowerShell permite-lhe definir e recuperar valores de variáveis em todos os âmbitos.
Escopos Locais
Para definir uma variável num âmbito local, use Set-Variable
e forneça-lhe um nome de variável local e um valor como mostrado abaixo.
PS> Set-Variable -Name a -Value 'foo'
O âmbito local é sempre o predefinido, por isso não usar o parâmetro Scope
irá sempre definir a variável no âmbito local.
Para recuperar o valor de uma variável com escopo local, use Get-Variable
fornecendo-lhe o nome.
PS> Get-Variable -Name aName Value---- -----a foo
Escopo Privado/Script/Global
Você usará os mesmos parâmetros (Name
e Value
) quando trabalhar com variáveis privadas, script e globais também. A única diferença é que desta vez você vai usar o parâmetro Escopo para definir explicitamente o escopo.
Os métodos para definir uma variável privada, script ou global são os mesmos. Basta substituir o valor passado para o parâmetro Scope
como Private
, Script
Global
.
PS> Set-Variable -Name a -Value 'foo' -Scope <Private|Script|Global>
Para recuperar o valor de um script ou de uma variável com o escopo global, use Get-Variable
fornecendo-lhe o nome e o escopo.
PS> Get-Variable -Name a -Scope <Script|Global>Name Value---- -----a foo
Nota: Você também pode referenciar escopos usando números de escopo em vez de nomes com o
Get
/Set-Variable
cmdlets.
Escopo “Prefacing”
Você também pode recuperar e definir variáveis em escopos usando um atalho. Em vez de usar o PowerShell cmdlets, você vai prefaciar o escopo para a variável ao fazer referência a ele.
Escopos locais
Desde que o escopo local é sempre o padrão, basta definir uma variável e o referenciamento irá definir e recuperar uma variável de escopo local
PS> $a = 'foo'PS> $afoo
Escopos privados/escritos/globais
Se você quiser definir e referenciar script ou escopos globais, você pode prefaciar as variáveis com o nome do escopo e um ponto-e-vírgula.
Por exemplo, para definir a variável $a
no escopo global, você pode prefaciar a com $global:
.
$global:a = 'foo'
O mesmo pode ser feito para uma variável com escopo de script.
$script:a = 'foo'
Após as variáveis serem definidas no escopo preferencial, você então as referenciaria da mesma forma. Observe também que você pode excluir o prefácio do escopo se o escopo definido for o escopo local.
PS> $global:a = 'foo'PS> $global:afooPS> $afoo
Escopos em Scriptblocks
PowerShell tem uma construção útil chamada scriptblocks. Os blocos de script permitem que você se mova por trechos de código e os execute em praticamente qualquer lugar.
Como um script PS1, os blocos de script são executados em seu próprio escopo de script. Quando você executa um scriptblock, você está essencialmente executando um script PS1.
Notice no exemplo abaixo onde uma variável é definida no escopo global e depois tenta sobrescrever em um escopo de script. Como você aprendeu acima, isso não vai funcionar porque um escopo filho não pode referenciar um escopo pai.
Este exemplo mostra que quando $a
é alterado no scriptblock, a definição da variável global para $a
não é alterada porque o scriptblock é um escopo filho do script.
Dot Sourcing Scripts (Troca de Escopos Locais)
PowerShell tem um conceito chamado dot-sourcing. Este é um método que lhe permite executar um script PS1 e trazer tudo o que seria script-scoped para o escopo local em vez disso.
Por meio da colocação de um ponto (.) antes de referenciar um script PS1 e executá-lo, este “ponto fontes” o conteúdo do script e traz tudo para o escopo local.
Para demonstrar, tenho novamente um script Test.ps1 que define uma variável como mostrado abaixo.
$a = 'Hello world!'
Numa consola PowerShell, defina um valor para uma variável $a
e depois o ponto fonte deste script como mostrado abaixo. Note que a variável original foi sobregravada. PowerShell “fundiu” os dois escopos locais.
Usando a propriedade AllScope (Option)
Você já viu como interagir com itens em escopos específicos, mas até agora cada item ainda está definido em um único escopo. Mas e se você não sabe em que escopo uma variável é definida?
Ao definir uma variável com o escopo Set-Variable
cmdlet, você pode colocar a variável em todos os escopos ao mesmo tempo. Para fazer isto, use o valor AllScope
para o parâmetro Option
.
Para demonstrar, o script Test.ps1 foi modificado para definir uma variável em todos os escopos. Essa variável é então gerada como mostrado abaixo.
Set-Variable -Name a -Value 'Hello world!' -Option AllScopeWrite-Output $a
Você pode então ver abaixo que um valor está sendo definido para $a no escopo global e o script Test.ps1 é executado. Entretanto, ao invés de não ter efeito, o valor de $a
foi sobrescrito. Não só foi definido no escopo do script (Write-Output $a
) como também foi sobrescrito no escopo global.
A opção AllScope
é útil, mas tenha cuidado. Esta opção essencialmente elimina o conceito de escopos e funde tudo junto.
Escopos de funções
Quando você executa uma função, todo o código dentro dessa função está em seu próprio escopo infantil. Os escopos de funções seguem o mesmo comportamento criança/parente dos outros escopos.
Disparar escopos separados para cada função é uma boa idéia. Ele permite um melhor controle sobre itens que não têm que se preocupar com itens conflitantes, Também dá o benefício adicional de limpeza automática de variáveis em uma função. Assim que a função estiver completa, todos os itens definidos na função serão limpos.
Para demonstrar, copie/colar a função abaixo directamente para a consola PowerShell.
Function Do-Thing { $var = 'bar'}
Após colar, execute a função. Note que você não pode acessar a variável $var
fora da função.
PS> Do-ThingPS> $var
Manter itens privados (Desabilitando a herança)
Tipicamente, se uma variável for definida no escopo dos pais, essa variável será definida no escopo dos filhos. Mas talvez você gostaria de usar um nome de variável mas esse nome já foi definido em um dos escopos a ser executado em uma sessão. Nesse caso, você pode escolher um nome de variável diferente ou definir a variável em um escopo privado tornando-a uma variável privada.
Uma maneira de usar escopos para reduzir conflitos é usar o escopo privado. O uso do escopo privado desabilita a herança naquela variável específica. Quando múltiplos escopos filhos são criados, esses escopos filhos não verão nenhuma variável definida em um escopo privado.
Um script Test.ps1 produz o valor de $a como mostrado abaixo.
Write-Output $a
Você pode ver abaixo Eu estou definindo uma variável com escopo privado no escopo global e então executando o script Test.ps1. Normalmente, quando você define uma variável no escopo parent, essa variável estará disponível no escopo child – não com uma variável de escopo privately-scoped.
No exemplo abaixo, você pode ver que o script child scope criado pela execução do script Test.ps1 não pôde ver a variável private-scoped $a
definida no escopo pai.
Unlike global scopes or the AllScope
option on the Set-Variable
cmdlet, private-scoped variables are an excellent way to compartmentalize items.
Melhores Práticas de Escopo
Pensando que definir variáveis no escopo global ou usando a opção AllScope
é o caminho a seguir é comum. Afinal de contas, todas as variáveis estão disponíveis em qualquer lugar. Não há necessidade de se preocupar com as complicações dos escopos. Embora isso proporcione liberdade adicional para acesso ao que é definido, pode rapidamente sair do controle e ficar difícil de solucionar problemas.
Em vez de tentar evitar o uso de escopos siga estas dicas:
- Em vez de especificar escopos em funções, use parâmetros para passar as informações necessárias para a função.
- Fique dentro do escopo local o máximo possível.
- Em vez de definir variáveis globais a partir de um script, use a opção
Write-Output
cmdlet para sair tudo e salvá-lo em uma variável quando necessário a partir do console.
O ponto principal aqui é abraçar escopos e aprender a usá-los a seu favor em vez de tentar contorná-los.
Leitura adicional
- Sobre funções avançadas e parâmetros de funções
- Usar variáveis de ambiente no PowerShell