Escopo no PowerShell define onde variáveis, funções e outros elementos são visíveis e podem ser acessados. Compreender escopo é essencial para escrever scripts modulares, evitar efeitos colaterais indesejados e reutilizar código de forma segura. Nesta aula, exploraremos os principais escopos, como controlá-los e as melhores práticas para gerenciá-los.

O PowerShell organiza o escopo em uma hierarquia: o escopo Global abrange toda a sessão, o escopo Script delimita um arquivo de script, e o escopo Local refere-se ao contexto atual (como uma função ou bloco). Por padrão, variáveis e funções são locais ao escopo onde são criadas, mas podemos usar modificadores ou técnicas como dot-sourcing para alterar esse comportamento.

Global, Script, Local

Escopo Global: É o escopo raiz da sessão do PowerShell. Variáveis e funções definidas no escopo global estão disponíveis em toda a sessão, inclusive em scripts e funções, a menos que sejam ocultadas por um escopo local. Exemplo: variáveis definidas no console ou carregadas via perfil.

Escopo Script: Cada arquivo de script (.ps1) tem seu próprio escopo de script. Variáveis e funções definidas em um script são, por padrão, visíveis apenas dentro daquele script, a menos que explicitamente exportadas ou modificadas. Isso ajuda a isolar o script do ambiente global.

Escopo Local: É o escopo atual em execução, como dentro de uma função, um bloco {} ou um script. Variáveis criadas dentro de uma função são locais a ela e não afetam o escopo chamador, a menos que sejam retornadas ou modificadas com modificadores de escopo.

Exemplo prático:

$global:var = "Global"  # Variável global
function Test-Scope {
    $script:var = "Script"  # Variável no escopo do script
    $local:var = "Local"    # Variável local à função
    Write-Host "Dentro da função: global=$global:var, script=$script:var, local=$local:var"
}
Test-Scope
Write-Host "Fora da função: global=$global:var, script=$script:var"
# A variável $local:var não existe fora da função

Modificadores ($script:, $global:)

Os modificadores de escopo permitem acessar ou modificar variáveis em escopos específicos. O prefixo $global: refere-se ao escopo global, enquanto $script: refere-se ao escopo do script atual. Eles podem ser usados tanto para leitura quanto para atribuição.

Exemplo de uso:

$global:count = 0
function Increment-Count {
    $global:count++  # Incrementa a variável global
}
Increment-Count
Write-Host $global:count  # Saída: 1

Sem o modificador, a variável $count dentro da função seria local e não alteraria a global. É importante usar esses modificadores com cuidado para evitar efeitos colaterais não intencionais.

Dot-sourcing

Dot-sourcing é uma técnica que executa um script no escopo atual (chamador), em vez de em um escopo de script filho. Isso faz com que todas as variáveis, funções e aliases definidos no script sejam adicionados ao escopo atual, como se tivessem sido digitados diretamente no console ou no script chamador.

Sintaxe: . \caminho\script.ps1 (ponto seguido de espaço e o caminho do script).

Exemplo:

# script.ps1 contém: $var = "Do script"
. .\script.ps1
Write-Host $var  # Saída: "Do script"

Sem o dot-sourcing, a variável $var seria local ao script e não estaria disponível após a execução. Dot-sourcing é útil para carregar funções de bibliotecas ou configurar ambientes, mas deve ser usado com cautela para não poluir o escopo global.

Boas práticas

  • Evite modificar o escopo global dentro de funções: Prefira retornar valores ou usar parâmetros [ref] para alterar variáveis externas. Isso torna o código mais previsível e fácil de depurar.
  • Use escopo de script para isolar scripts: Variáveis internas de um script não devem vazar para o escopo global, a menos que explicitamente desejado. Use $script: quando precisar compartilhar entre funções do mesmo script.
  • Dot-sourcing com moderação: Use dot-sourcing apenas para scripts de configuração ou carregamento de módulos que precisam expor funções no escopo atual. Prefira módulos (.psm1) para bibliotecas reutilizáveis.
  • Documente o uso de escopo: Em scripts compartilhados, indique claramente quais variáveis são globais ou de script para evitar confusão.
  • Prefira variáveis locais: Dentro de funções, use variáveis locais (sem prefixo) para evitar conflitos. Se precisar de persistência entre chamadas, considere usar $script: ou parâmetros estáticos.

Referências

Exercícios

  1. Crie uma função chamada Set-GlobalVar que aceita um parâmetro e define uma variável global com esse valor. Teste chamando a função e verificando a variável global.

    ✓ Resposta:
    function Set-GlobalVar {
        param([string]$Name, [object]$Value)
        Set-Variable -Name $Name -Value $Value -Scope Global
    }
    Set-GlobalVar -Name "myGlobal" -Value 42
    Write-Host $global:myGlobal  # Saída: 42
  2. Escreva um script que define uma variável no escopo do script e, em uma função, tente modificá-la usando o modificador apropriado. Verifique o valor após a execução.

    ✓ Resposta:
    $script:myVar = "original"
    function Update-ScriptVar {
        $script:myVar = "modificado"
    }
    Update-ScriptVar
    Write-Host $script:myVar  # Saída: modificado
  3. Utilize dot-sourcing para carregar um script que define funções e, em seguida, chame uma dessas funções no escopo atual. Crie o script e o código que o carrega.

    ✓ Resposta:
    # script.ps1:
    function Get-Hello {
        "Hello from dot-sourced script"
    }
    # Carregamento:
    . .\script.ps1
    Get-Hello  # Saída: Hello from dot-sourced script
  4. Explique a diferença entre usar $global:var e $script:var dentro de uma função definida em um script. Dê um exemplo.

    ✓ Resposta:

    $global:var refere-se a uma variável no escopo global da sessão, enquanto $script:var refere-se a uma variável no escopo do script atual. Dentro de uma função em um script, $global:var modifica a variável global, enquanto $script:var modifica a variável do script. Exemplo:

    $global:g = "global"
    $script:s = "script"
    function Test {
        $global:g = "alterado global"
        $script:s = "alterado script"
    }
    Test
    Write-Host $global:g  # alterado global
    Write-Host $script:s  # alterado script
  5. Identifique e corrija o problema no código a seguir: function Increment { $count++ } $count=0; Increment; Write-Host $count. O que é necessário para que a variável seja incrementada?

    ✓ Resposta:

    O problema é que $count dentro da função é uma nova variável local, não a global. Para incrementar a variável global, use $global:count++. Código corrigido:

    function Increment { $global:count++ }
    $global:count = 0
    Increment
    Write-Host $global:count  # Saída: 1