Funções no PowerShell
LidoEsta aula ensina a criar e usar funções no PowerShell, cobrindo declaração, chamada, parâmetros e a importância do fluxo de saída para o retorno de valores. Inclui exemplos práticos, boas práticas e exercícios com respostas.
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-SaudacaoSe 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,4Retorno (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-Hostpara mensagens informativas que não devem ser capturadas. - Use
Write-Outputapenas 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
$nullou useOut-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-DadosSe 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 encerraBoas 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-Hostem funções que devem retornar dados; prefiraWrite-VerboseouWrite-Debugpara informações de diagnóstico, controláveis pelo usuário.
Exercícios
- Crie uma função chamada
Get-Dobroque aceite um número inteiro como parâmetro obrigatório e retorne o dobro desse número. - Escreva uma função chamada
Teste-Parque receba um número e retorne$truese for par e$falsecaso contrário. - 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. - 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" } - Escreva uma função chamada
New-SaudacaoPersonalizadaque receba parâmetrosNome(obrigatório) eSobrenome(opcional) e retorne uma string de saudação completa (ex.: "Olá, Maria Silva!").
function Get-Dobro {
param(
[Parameter(Mandatory=$true)]
[int]$Numero
)
$Numero * 2
}function Teste-Par {
param([int]$Numero)
return (($Numero % 2) -eq 0)
}function Get-NomesComA {
param([string[]]$Nomes)
$Nomes | Where-Object { $_ -like 'A*' }
}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
}function New-SaudacaoPersonalizada {
param(
[Parameter(Mandatory=$true)]
[string]$Nome,
[string]$Sobrenome = ''
)
$nomeCompleto = $Nome.Trim()
if ($Sobrenome) { $nomeCompleto += ' ' + $Sobrenome.Trim() }
"Olá, $nomeCompleto!"
}