Funções são blocos de código reutilizáveis que permitem organizar scripts, reduzir duplicação e tornar a lógica mais clara. No PowerShell, funções são fundamentais para criar módulos e ferramentas robustas. Nesta aula, você aprenderá desde a sintaxe básica até os detalhes sutis de como o PowerShell lida com a saída de dados, essencial para escrever funções que retornam valores corretamente.

Diferente de outras linguagens, o PowerShell trata a saída de qualquer comando dentro da função como parte do retorno. Isso é poderoso, mas exige cuidado para não retornar informações indesejadas. Vamos explorar isso a fundo.

Declaração

Para declarar uma função no PowerShell, usa-se a palavra-chave function seguida do nome e de um bloco de script entre chaves {}. O nome da função deve seguir as regras de nomenclatura do PowerShell: pode conter letras, números, underscore e hífen, mas não pode começar com número. Por convenção, usa-se o verbo no infinitivo (como Get, Set, New) seguido de um substantivo, no formato Verbo-Substantivo, facilitando a descoberta e a padronização.

Exemplo simples:

function Get-Saudacao {
    Write-Host "Olá, mundo!"
}

Essa função não recebe parâmetros e apenas exibe uma mensagem. É importante notar que Write-Host exibe diretamente no console, mas não envia a saída para o pipeline — isso será crucial quando falarmos de retorno.

Funções podem ser definidas em um script, no console ou em módulos. Quando definidas em um script, ficam disponíveis apenas durante a execução daquele script, a menos que sejam dot-sourced ou exportadas de um módulo.

Chamada

Para chamar uma função, basta usar o nome dela seguido de parênteses (se houver parâmetros) ou apenas o nome, como se fosse um comando nativo. No PowerShell, as funções são tratadas como comandos, então podemos chamar Get-Saudacao simplesmente digitando o nome.

# Chamando a função definida acima
Get-Saudacao

Se a função tiver parâmetros, podemos passá-los por posição ou por nome. Por exemplo, se tivermos uma função Set-Saudacao que aceita um parâmetro Nome, podemos chamar assim:

function Set-Saudacao($Nome) {
    Write-Host "Olá, $Nome!"
}

# Chamada posicional
Set-Saudacao "Maria"

# Chamada por nome
Set-Saudacao -Nome "João"

Também é possível usar a sintaxe de parênteses: Set-Saudacao("Maria"), mas isso não é recomendado porque pode causar confusão, especialmente com arrays. Prefira sempre a sintaxe de comando.

Funções podem ser usadas em pipelines, desde que processem entrada da forma correta (usando process), mas isso é um tópico avançado. Por enquanto, entenda que a chamada pode ser feita diretamente ou dentro de expressões maiores, como atribuições: $resultado = MinhaFuncao.

Parâmetros básicos

Parâmetros permitem que funções recebam dados de entrada e se comportem de maneira dinâmica. A forma mais simples de declarar parâmetros é listá-los entre parênteses após o nome da função, como vimos: function Set-Saudacao($Nome). Podemos ter vários parâmetros separados por vírgula.

No entanto, a forma recomendada e mais flexível é usar o bloco param() no início da função. Isso permite definir atributos como obrigatoriedade, tipo, valores padrão e validações.

function New-Cumprimento {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Nome,
        [int]$Vezes = 1
    )

    for ($i = 0; $i -lt $Vezes; $i++) {
        Write-Host "Olá, $Nome!"
    }
}

Explicação: $Nome é obrigatório (Mandatory) e do tipo string; $Vezes é opcional, do tipo int e com valor padrão 1. O usuário pode chamar assim:

New-Cumprimento -Nome "Ana" -Vezes 3
New-Cumprimento -Nome "Pedro"

Outros atributos comuns: [ValidateSet(...)] para restringir valores, [ValidateRange(...)] para números, e [ValidateNotNullOrEmpty()] para strings. Você também pode tornar um parâmetro posicional definindo a posição na chamada, mas é mais seguro usar nomes.

Quando não se sabe quantos argumentos virão, use [Parameter(ValueFromRemainingArguments=$true)] ou o tipo [string[]] para aceitar uma lista. Por exemplo:

function Get-Soma {
    param([int[]]$Numeros)
    $soma = 0
    foreach ($n in $Numeros) { $soma += $n }
    Write-Output $soma
}

Get-Soma -Numeros 1,2,3,4

Retorno (cuidado com saída)

No PowerShell, tudo o que a função envia para a saída (pipeline) é considerado retorno. Isso inclui o resultado de comandos como Write-Output, Write-Host (não, na verdade não), e qualquer expressão que produza saída. A palavra-chave return existe, mas ela apenas encerra a função e opcionalmente define um valor de saída — mas não é obrigatória. Na prática, qualquer valor que você “emite” é retornado.

Isso causa um dos erros mais comuns: funções que retornam mais do que o esperado porque comandos internos como Write-Host ou até mesmo atribuições podem vazar saída. Por exemplo:

function Get-Mensagem {
    Write-Host "Calculando..."
    $resultado = 5 + 3
    Write-Output $resultado
}

$retorno = Get-Mensagem
Write-Host "Retorno: $retorno"

O Write-Host exibe a mensagem diretamente, mas não vai para o pipeline, então a variável $retorno conterá apenas o número 8. Porém, se usássemos Write-Output "Calculando...", essa string entraria no pipeline e a função retornaria dois valores (a string e o número).

Para evitar retornos indesejados, siga estas boas práticas:

  • Use Write-Host para mensagens informativas que não devem ser capturadas.
  • Use Write-Output apenas para os dados que deseja retornar.
  • Se precisar retornar vários valores, colete-os em um array ou objeto e emita uma única vez.
  • Para suprimir a saída de um comando interno, redirecione para $null ou use Out-Null.

Exemplo de retorno múltiplo indesejado:

function Get-Dados {
    Get-Process
    Get-Service
}
# Retorna TODOS os processos e serviços (dois objetos diferentes)
$resultados = Get-Dados

Se a intenção é retornar apenas um tipo, separe ou filtre. Para retornar um objeto personalizado, use [PSCustomObject]:

function Get-Resumo {
    $proc = Get-Process -Name "powershell"
    $serv = Get-Service -Name "Spooler"
    [PSCustomObject]@{
        Processos = $proc.Count
        Servico = $serv.Status
    }
}

Lembre-se: o comando return pode ser usado para sair imediatamente, mas o valor passado a ele também é enviado para a saída. Por exemplo:

function Teste {
    if ($true) { return "sim" }
    "não"
}
# Retorna "sim" e encerra

Boas práticas e observações finais

Ao criar funções no PowerShell, lembre-se de:

  • Usar nomes no padrão Verbo-Substantivo (ex.: Get-Process, Set-Variable).
  • Sempre usar o bloco param() para declarar parâmetros, mesmo que vazio, para consistência.
  • Documentar a função com comentários baseados em <# ... #> e, se quiser, com ajuda baseada em comentários (Get-Help).
  • Testar a função em diferentes cenários para garantir que a saída seja previsível.
  • Evitar Write-Host em funções que devem retornar dados; prefira Write-Verbose ou Write-Debug para informações de diagnóstico, controláveis pelo usuário.

Exercícios

  1. Crie uma função chamada Get-Dobro que aceite um número inteiro como parâmetro obrigatório e retorne o dobro desse número.
  2. ✓ Resposta:
    function Get-Dobro {
        param(
            [Parameter(Mandatory=$true)]
            [int]$Numero
        )
        $Numero * 2
    }
  3. Escreva uma função chamada Teste-Par que receba um número e retorne $true se for par e $false caso contrário.
  4. ✓ Resposta:
    function Teste-Par {
        param([int]$Numero)
        return (($Numero % 2) -eq 0)
    }
  5. Crie uma função que aceite uma lista de nomes (array de strings) e retorne apenas os nomes que começam com a letra "A". Use Where-Object.
  6. ✓ Resposta:
    function Get-NomesComA {
        param([string[]]$Nomes)
        $Nomes | Where-Object { $_ -like 'A*' }
    }
  7. Explique por que a seguinte função retorna três valores e como corrigi-la para retornar apenas a soma.
    function Get-SomaErrada($a, $b) {
        Write-Output "Somando..."
        $a + $b
        Write-Output "Fim"
    }
  8. ✓ Resposta: A função retorna a string "Somando...", o resultado da soma e a string "Fim" porque cada Write-Output envia um objeto para a saída. Para corrigir, remova os Write-Output extras e apenas emita a soma, ou use Write-Host para mensagens informativas. Exemplo corrigido:
    function Get-SomaCorreta($a, $b) {
        Write-Host "Somando..."
        $a + $b
    }
  9. Escreva uma função chamada New-SaudacaoPersonalizada que receba parâmetros Nome (obrigatório) e Sobrenome (opcional) e retorne uma string de saudação completa (ex.: "Olá, Maria Silva!").
  10. ✓ Resposta:
    function New-SaudacaoPersonalizada {
        param(
            [Parameter(Mandatory=$true)]
            [string]$Nome,
            [string]$Sobrenome = ''
        )
        $nomeCompleto = $Nome.Trim()
        if ($Sobrenome) { $nomeCompleto += ' ' + $Sobrenome.Trim() }
        "Olá, $nomeCompleto!"
    }

Referências