Parâmetros do PowerShell: Desbloqueie o Poder da Scripting

Todos os comandos do PowerShell podem ter um ou mais parâmetros, às vezes chamados de argumentos. Se você não está usando parâmetros do PowerShell em suas funções do PowerShell, você não está escrevendo um bom código do PowerShell!

Neste artigo, você vai aprender praticamente tudo sobre a criação e uso de parâmetros ou argumentos do PowerShell!

Este é um exemplo do meu livro PowerShell para SysAdmins. Se você quer aprender PowerShell ou aprender alguns truques do ofício, confira!

Por que você precisa de um parâmetro?

Quando você começa a criar funções, você tem a opção de incluir parâmetros ou não e como esses parâmetros funcionam.

Vamos dizer que você tem uma função que instala o Microsoft Office. Talvez ela chame o instalador do Office silenciosamente dentro da função. O que a função faz não importa para nossos propósitos. A função básica se parece com isso com o nome da função e o bloco de script.

function Install-Office {
    ## execute o instalador silencioso aqui
}

Neste exemplo, você simplesmente executou Install-Office sem parâmetros e ele faz o seu trabalho.

Não importava se a função Install-Office tinha parâmetros ou não. Aparentemente, não tinha nenhum parâmetro obrigatório; caso contrário, o PowerShell não teria nos deixado executá-lo sem usar um parâmetro.

Quando usar um parâmetro do PowerShell

O Office tem muitas versões diferentes. Talvez seja necessário instalar o Office 2013 e 2016. Atualmente, você não tem uma maneira de especificar isso. Você poderia alterar o código da função toda vez que quisesse mudar o comportamento.

Por exemplo, você poderia criar duas funções separadas para instalar diferentes versões.

function Install-Office2013 {
    Write-Host 'I installed Office 2013. Yippee!'
}

function Install-Office2016 {
    Write-Host 'I installed Office 2016. Yippee!'
}

Fazer isso funciona, mas não é escalável. Isso obriga você a criar uma função separada para cada versão do Office que é lançada. Você terá que duplicar muito código quando não for necessário.

Em vez disso, você precisa de uma maneira de passar valores diferentes em tempo de execução para mudar o comportamento da função. Como você faz isso?

Sim! Parâmetros ou o que algumas pessoas chamam de argumentos.

Como gostaríamos de instalar diferentes versões do Office sem alterar o código toda vez, você precisa adicionar pelo menos um parâmetro a esta função.

Antes de pensar rapidamente em um parâmetro do PowerShell para usar, é essencial se perguntar primeiro: “Qual é a menor alteração ou alterações que você espera que sejam necessárias nesta função?”.

Lembre-se de que você precisa executar esta função novamente sem alterar nenhum código dentro dela. Neste exemplo, o parâmetro provavelmente está claro para você; você precisa adicionar um parâmetro Versão. Mas, quando você tem uma função com dezenas de linhas de código, a resposta não será muito aparente. Contanto que você responda a essa pergunta da forma mais precisa possível, sempre ajudará.

Então, você sabe que precisa de um parâmetro Versão. E agora? Agora você pode adicionar um, mas como em qualquer grande linguagem de programação, existem várias maneiras de resolver esse problema.

Neste tutorial, vou mostrar a “melhor” maneira de criar parâmetros com base na minha experiência de quase uma década com o PowerShell. No entanto, saiba que esta não é a única maneira de criar um parâmetro.

Existe algo chamado de parâmetros posicionais. Esses parâmetros permitem que você passe valores para os parâmetros sem especificar o nome do parâmetro. Os parâmetros posicionais funcionam, mas não são considerados “boas práticas”. Por quê? Porque são mais difíceis de ler, especialmente quando você tem muitos parâmetros definidos em uma função.

Criando um Parâmetro Simples no PowerShell

Para criar um parâmetro em uma função, são necessários dois componentes principais: um bloco de parâmetros e o próprio parâmetro. Um bloco de param é definido pela palavra-chave param seguida de um conjunto de parênteses.

An example of a param block
function Install-Office { [CmdletBinding()] param() Write-Host 'I installed Office 2016. Yippee!' }

Neste ponto, a funcionalidade real da função não mudou nada. Apenas montamos uma estrutura básica, preparando-nos para o primeiro parâmetro.

Assim que tivermos o bloco param no lugar, agora você irá criar o parâmetro. O método que estou sugerindo para você criar um parâmetro inclui o bloco Parameter, seguido do tipo de parâmetro e, em seguida, o nome da variável do parâmetro abaixo.

An example of a param block
function Install-Office { [CmdletBinding()] param( [Parameter()] [string]$Version ) Write-Host 'I installed Office 2016. Yippee!' }

Agora criamos um parâmetro de função no PowerShell, mas o que exatamente aconteceu aqui?

O bloco Parameter é uma parte opcional, mas recomendada, de cada parâmetro. Assim como o bloco param, é uma “estrutura de função” que prepara o parâmetro para adicionar funcionalidades adicionais. A segunda linha é onde você define o tipo de parâmetro.

Neste caso, optamos por converter o parâmetro Version para uma string. Definir um tipo explícito significa que qualquer valor passado para este parâmetro sempre tentará ser “convertido” para uma string, se ainda não o for.

O tipo não é obrigatório, mas é altamente recomendado. Definir explicitamente o tipo do parâmetro reduzirá significativamente muitas situações indesejadas no futuro. Confie em mim.

Agora que você definiu o parâmetro, pode executar o comando Install-Office com o parâmetro Version, passando uma string de versão como 2013. O valor passado para o parâmetro Version é às vezes chamado de argumentos ou valores do parâmetro.

Passing a Parameter to the Function
PS> Install-Office -Version 2013 I installed Office 2016. Yippee!

O que está acontecendo aqui afinal? Você disse que queria instalar a versão 2013, mas ainda está dizendo que instalou a versão 2016. Quando você adiciona um parâmetro, lembre-se de alterar o código da função para uma variável. Quando o parâmetro é passado para a função, essa variável será expandida para ser qualquer valor que foi passado.

Altere o texto estático de 2016 e substitua pelo variável do parâmetro Version e converta as aspas simples para aspas duplas para que a variável seja expandida.

Modifying function code account for a parameter
function Install-Office { [CmdletBinding()] param( [Parameter()] [string]$Version ) Write-Host "I installed Office $Version. Yippee!" }

Agora você pode ver que qualquer valor que você passar para o parâmetro Version será então passado para a função como a variável $Version.

O Atributo de Parâmetro Obrigatório

Lembre-se de que mencionei que a linha [Parameter()] era apenas “encanamento da função” e precisava preparar a função para trabalhos futuros? Adicionar atributos ao parâmetro é o trabalho adicional ao qual me referi anteriormente.

A parameter doesn’t have to be a placeholder for a variable. PowerShell has a concept called parameter attributes and parameter validation. Parameter attributes change the behavior of the parameter in a lot of different ways.

Por exemplo, um dos atributos de parâmetro mais comuns que você definirá é a palavra-chave Mandatory. Por padrão, você poderia chamar a função Install-Office sem usar o parâmetro Version e ela seria executada sem problemas. O parâmetro Version seria opcional. Concedido, ele não expandiria a variável $Version dentro da função porque não havia valor, mas ainda assim seria executado.

Muitas vezes, ao criar um parâmetro, você desejará que o usuário sempre use esse parâmetro. Você dependerá do valor do parâmetro em algum lugar do código da função e, se o parâmetro não for passado, a função falhará. Nestes casos, você deseja forçar o usuário a passar o valor do parâmetro para sua função. Você quer que esse parâmetro se torne obrigatório.

Forçar os usuários a usar um parâmetro é simples depois de ter a estrutura básica construída como você tem aqui. Você precisa incluir a palavra-chave Mandatory dentro dos parênteses do parâmetro. Uma vez feito isso, a execução da função sem o parâmetro será interrompida até que um valor tenha sido inserido.

Using a mandatory parameter
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Version ) Write-Host "I installed Office $Version. Yippee!" } PS> Install-Office cmdlet Install-Office at command pipeline position 1 Supply values for the following parameters: Version:

A função aguardará até que você especifique um valor para o parâmetro Version. Depois de fazer isso e pressionar Enter, o PowerShell executará a função e seguirá em frente. Se você fornecer um valor para o parâmetro, o PowerShell não solicitará o parâmetro toda vez.

Atributos de Validação de Parâmetros do PowerShell

Fazer um parâmetro ser obrigatório é um dos atributos de parâmetro mais comuns que você pode adicionar, mas também é possível usar atributos de validação de parâmetros. Na programação, é sempre essencial restringir a entrada do usuário o máximo possível. Limitar as informações que os usuários (ou até mesmo você!) podem passar para suas funções ou scripts eliminará código desnecessário dentro da sua função que precisa lidar com todo tipo de situação.

Aprendendo com Exemplos

Por exemplo, na função Install-Office, eu demonstrei passar o valor 2013 para ela porque eu sabia que funcionaria. Eu escrevi o código! Estou supondo (nunca faça isso no código!) que é óbvio que qualquer pessoa que saiba algo especificaria a versão como sendo 2013 ou 2016. Bem, o que é óbvio para você pode não ser tão óbvio para outras pessoas.

Se você quiser ser técnico sobre as versões, provavelmente seria mais preciso especificar a versão 2013 como 15.0 e 2016 como 16.0 se a Microsoft ainda estivesse usando o esquema de numeração que eles usaram no passado. Mas e se, já que você está assumindo que eles vão especificar uma versão de 2013 ou 2016, você tem código dentro da função que procura por pastas com essas versões ou algo parecido?

Abaixo está um exemplo de onde você pode estar usando a string $Version em um caminho de arquivo. Se alguém passar um valor que não complete um nome de pasta de Office2013 ou Office2016, isso falhará ou fará algo pior, como remover pastas inesperadas ou alterar coisas que você não previu.

Assuming Parameter Values
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Version ) Get-ChildItem -Path "\\SRV1\Installers\Office$Version" } PS> Install-Office -Version '15.0' Get-ChildItem : Cannot find path '\SRV1\Installers\Office15.0' because it does not exist. At line:7 char:5 Get-ChildItem -Path "\\SRV1\Installers\Office$Version" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CategoryInfo : ObjectNotFound: (\SRV1\Installers\Office15.0:String) [Get-ChildItem], ItemNotFoundExcep tion FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Para limitar o usuário ao que você espera que ele insira, você pode adicionar alguma validação de parâmetro no PowerShell.

Usando o atributo de validação de parâmetro ValidateSet

Existem vários tipos de validação de parâmetro que você pode usar. Para obter uma lista completa, execute Get-Help about_Functions_Advanced_Parameters. Neste exemplo, o atributo ValidateSet provavelmente seria o melhor.

O atributo de validação ValidateSet permite que você especifique uma lista de valores que são permitidos como valor do parâmetro. Como estamos apenas considerando a string 2013 ou 2016, gostaria de garantir que o usuário só possa especificar esses valores. Caso contrário, a função falhará imediatamente, notificando o usuário do motivo.

Você pode adicionar atributos de validação de parâmetro logo abaixo da palavra-chave Parameter original. Neste exemplo, dentro dos parênteses do atributo do parâmetro, você tem uma matriz de itens; 2013 e 2016. Um atributo de validação de parâmetro informa ao PowerShell que os únicos valores válidos para Versão são 2013 ou 2016. Se você tentar passar algo além do que está no conjunto, receberá um erro informando que você só tem um número específico de opções disponíveis.

Using the ValidateSet parameter validation attribute
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateSet('2013','2016')] [string]$Version ) Get-ChildItem -Path "\\SRV1\Installers\Office$Version" } PS> Install-Office -Version 15.0 Install-Office : Cannot validate argument on parameter 'Version'. The argument "15.0" does not belong to the set "2013,2016" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again. At line:1 char:25 Install-Office -Version 15.0 ~~~~ CategoryInfo : InvalidData: (:) [Install-Office], ParameterBindingValidationException FullyQualifiedErrorId : ParameterArgumentValidationError,Install-Office

O atributo ValidateSet é um atributo de validação comum de usar. Para obter uma análise completa de todas as maneiras pelas quais os valores dos parâmetros podem ser restritos, consulte o tópico de ajuda Functions_Advanced_Parameters executando Get-Help about_Functions_Advanced_Parameters.

Conjuntos de Parâmetros

Suponha que você queira que apenas certos parâmetros do PowerShell sejam usados com outros parâmetros. Talvez você tenha adicionado um parâmetro Path à função Install-Office. Este caminho instalará qualquer versão do instalador. Neste caso, você não deseja que o usuário use o parâmetro Version.

Você precisa de conjuntos de parâmetros.

Os parâmetros podem ser agrupados em conjuntos que só podem ser usados com outros parâmetros no mesmo conjunto. Usando a função abaixo, agora você pode usar tanto o parâmetro Version quanto o parâmetro Path para obter o caminho para o instalador.

function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(Mandatory)]
        [string]$Path
    )
    
    if ($Version) {
        Get-ChildItem -Path "\\SRV1\Installers\Office$Version"
    } elseif ($Path) {
        Get-ChildItem -Path $Path
    }
}

Isso cria um problema, no entanto, porque o usuário poderia usar ambos os parâmetros. Além disso, como ambos os parâmetros são obrigatórios, eles serão obrigados a usar ambos quando isso não é o que você deseja. Para corrigir isso, podemos colocar cada parâmetro em um conjunto de parâmetros como abaixo.

function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'ByVersion')]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(Mandatory, ParameterSetName = 'ByPath')]
        [string]$Path
    )
    
    if ($Version) {
        Get-ChildItem -Path "\\SRV1\Installers\Office$Version"
    } elseif ($Path) {
        Get-ChildItem -Path $Path
    }
}

Ao definir um nome de conjunto de parâmetros em cada parâmetro, isso permite que você controle grupos de parâmetros juntos.

O Conjunto de Parâmetros Padrão

E se o usuário tentar executar Install-Office sem parâmetros? Isso não é considerado, e você verá uma mensagem de erro amigável.

No parameter set

Para corrigir isso, você precisará definir um conjunto de parâmetros padrão dentro da área de CmdletBinding(). Isso diz à função para escolher um conjunto de parâmetros para usar se nenhum parâmetro for usado explicitamente, alterando [CmdletBinding()] para [CmdletBinding(DefaultParameterSetName = 'ByVersion')]

Agora, sempre que você executar Install-Office, ele solicitará o parâmetro Versão pois estará usando esse conjunto de parâmetros.

Entrada de Pipeline

Até agora, nos exemplos, você tem criado funções com um parâmetro do PowerShell que só pode ser passado usando a sintaxe típica -NomeParâmetro Valor. Mas, como você já aprendeu, o PowerShell possui um pipeline intuitivo que permite passar objetos de um comando para outro sem usar a sintaxe “típica”.

Quando você usa o pipeline, você “encadeia” comandos com o símbolo de pipe | permitindo que um usuário envie a saída de um comando como Get-Service para Start-Service como um atalho para passar o parâmetro Nome para Start-Service.

O “Método Antigo” Usando um Loop

Na função personalizada com a qual você está trabalhando, você está instalando o Office e tem um parâmetro Versão. Vamos dizer que você tem uma lista de nomes de computadores em um arquivo CSV em uma linha com a versão do Office que precisa ser instalada neles na segunda linha. O arquivo CSV se parece com isso:

ComputerName,Version
PC1,2016
PC2,2013
PC3,2016

Você gostaria de instalar a versão do Office que está ao lado de cada computador nesse computador.

Primeiro, você terá que adicionar um parâmetro ComputerName à função para passar um nome de computador diferente para cada iteração da função. Abaixo, eu criei algum pseudocódigo que representa algum código que pode estar na função fictícia e adicionei uma instância de Write-Host para ver como as variáveis se expandem dentro da função.

Adding the ComputerName parameter
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateSet('2013','2016')] [string]$Version, [Parameter()] [string]$ComputerName ) <# ## Conecte-se ao remoto com algum código aqui Invoke-Command -ComputerName $ComputerName -ScriptBlock { ## Faça coisas para instalar a versão do Office neste computador Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version } #> Write-Host "I am installing Office version [$Version] on computer [$ComputerName]" }

Assim que você tiver adicionado o parâmetro ComputerName à função; você poderia fazer isso lendo o arquivo CSV e passando os valores do nome do computador e da versão para a função Install-Office.

$computers = Import-Csv -Path 'C:\ComputerOfficeVersions.csv'
foreach ($pc in $computers) {
    Install-Office -Version $_.Version -ComputerName $_.ComputerName
}

Criando Entrada de Pipeline para Parâmetros

Este método de ler as linhas do CSV e usar um loop para passar as propriedades de cada linha para a função é a forma “antiga” de fazer isso. Nesta seção, você quer abandonar completamente o foreach loop e usar o pipeline em vez disso.

Como está, a função não suporta o pipeline de forma alguma. Faria sentido intuitivo supor que você poderia passar cada nome de computador e versão para a função usando o pipeline. Abaixo, estamos lendo o CSV e passando-o diretamente para Install-Office, mas isso não funciona.

No function pipeline input defined
PS> Import-Csv -Path 'C:\ComputerOfficeVersions.csv' | Install-Office

Você pode assumir o que quiser, mas isso não faz com que funcione magicamente. Estamos sendo solicitados pelo parâmetro Version quando você sabe que Import-Csv está enviando isso como uma propriedade do objeto. Por que não está funcionando? Porque você ainda não adicionou suporte ao pipeline.

Há dois tipos de entrada de pipeline em uma função do PowerShell; PorValor (objeto inteiro) e PorNomeDePropriedade (uma única propriedade do objeto). Qual você acha que é a melhor maneira de juntar a saída do Import-Csv com a entrada do Install-Office?

Sem nenhuma refatoração, você poderia usar o método PorNomeDePropriedade, afinal, Import-Csv já está retornando as propriedades Version e ComputerName já que são colunas no CSV.

Adicionar suporte ao pipeline para uma função personalizada é muito mais simples do que você pode estar pensando. É apenas um atributo de parâmetro representado por uma das duas palavras-chave; ValueFromPipeline ou ValueFromPipelineByPropertyName.

No exemplo, você gostaria de vincular as propriedades ComputerName e Version retornadas do Import-Csv aos parâmetros Version e ComputerName do Install-Office, então você usará ValueFromPipelineByPropertyName.

Como gostaríamos de vincular ambos os parâmetros, você adicionará essa palavra-chave a ambos os parâmetros conforme mostrado abaixo e executará a função usando o pipeline.

Adding Pipeline Support
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName)] [ValidateSet('2013','2016')] [string]$Version, [Parameter(ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string]$ComputerName ) <# ## Conecte-se remotamente com algum código aqui Invoke-Command -ComputerName $ComputerName -ScriptBlock { ## Faça algo para instalar a versão do Office neste computador Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version } #> Write-Host "I am installing Office version [$Version] on computer [$ComputerName]" }

Isso é estranho. Só rodou para a última linha no CSV. O que está acontecendo? Ele executou a função apenas para a última linha porque você pulou um conceito que não é necessário ao construir funções sem suporte de pipeline.

Não Esqueça do Bloco de Processo!

Quando você precisa criar uma função que envolve suporte de pipeline, você deve incluir (no mínimo) um bloco “embutido” dentro da sua função chamado. process. Este bloco de processo diz ao PowerShell que ao receber entrada de pipeline, execute a função para cada iteração. Por padrão, ele executará apenas a última.

Tecnicamente, você poderia adicionar outros blocos como begin e end também, mas os scripters não os usam com tanta frequência.

Para dizer ao PowerShell para executar esta função para cada objeto que entra, vou adicionar um bloco process que inclui o código dentro dele.

Adding the process block
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName)] [ValidateSet('2013','2016')] [string]$Version, [Parameter(ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string]$ComputerName ) process { <# ## Conecte-se remotamente com algum código aqui Invoke-Command -ComputerName $ComputerName -ScriptBlock { ## Faça algo para instalar a versão do Office neste computador Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version } #> Write-Host "I am installing Office version [$Version] on computer [$ComputerName]" } }

Agora você pode ver que as propriedades Version e ComputerName de cada objeto retornadas de Import-Csv foram passadas para Install-Office e vinculadas aos parâmetros Version e ComputerName.

Recursos

Para se aprofundar em como os parâmetros da função funcionam, confira meu post no blog sobre funções PowerShell.

I also encourage you to check my Pluralsight course entitled Building Advanced PowerShell Functions and Modules for an in-depth breakdown of everything there is to know about PowerShell functions, function parameters, and PowerShell modules.

Source:
https://adamtheautomator.com/powershell-parameter/