Como lidar com argumentos de linha de comando no PowerShell

494

Qual é a "melhor" maneira de lidar com argumentos de linha de comando?

Parece que existem várias respostas sobre qual é o "melhor" caminho e, como resultado, estou preso em como lidar com algo tão simples como:

script.ps1 /n name /d domain

E

script.ps1 /d domain /n name.

Existe um plugin que possa lidar com isso melhor? Eu sei que estou reinventando a roda aqui.

Obviamente, o que eu já tenho não é bonito e certamente não é o "melhor", mas funciona .. e é FEIO.

for ( $i = 0; $i -lt $args.count; $i++ ) {
    if ($args[ $i ] -eq "/n"){ $strName=$args[ $i+1 ]}
    if ($args[ $i ] -eq "-n"){ $strName=$args[ $i+1 ]}
    if ($args[ $i ] -eq "/d"){ $strDomain=$args[ $i+1 ]}
    if ($args[ $i ] -eq "-d"){ $strDomain=$args[ $i+1 ]}
}
Write-Host $strName
Write-Host $strDomain
Aaron Wurthmann
fonte

Respostas:

917

Você está reinventando a roda. Os scripts normais do PowerShell têm parâmetros que começam com -, comoscript.ps1 -server http://devserver

Então você lida com eles na paramseção no início do arquivo.

Você também pode atribuir valores padrão aos seus parâmetros, lê-los no console, se não estiverem disponíveis, ou interromper a execução do script:

 param (
    [string]$server = "http://defaultserver",
    [Parameter(Mandatory=$true)][string]$username,
    [string]$password = $( Read-Host "Input password, please" )
 )

Dentro do script você pode simplesmente

write-output $server

pois todos os parâmetros se tornam variáveis ​​disponíveis no escopo do script.

Neste exemplo, $serverobtém um valor padrão se o script for chamado sem ele, o script será interrompido se você omitir o -usernameparâmetro e solicitará a entrada do terminal se -passwordfor omitido.

Atualização: você também pode passar um "sinalizador" (um parâmetro booleano verdadeiro / falso) para um script do PowerShell. Por exemplo, seu script pode aceitar uma "força" onde o script é executado em um modo mais cuidadoso quando a força não é usada.

A palavra-chave para isso é o [switch]tipo de parâmetro:

 param (
    [string]$server = "http://defaultserver",
    [string]$password = $( Read-Host "Input password, please" ),
    [switch]$force = $false
 )

Dentro do script, você trabalharia com ele assim:

if ($force) {
  //deletes a file or does something "bad"
}

Agora, ao chamar o script, você definiria o parâmetro switch / flag assim:

.\yourscript.ps1 -server "http://otherserver" -force

Se você deseja declarar explicitamente que o sinalizador não está definido, há uma sintaxe especial para esse

.\yourscript.ps1 -server "http://otherserver" -force:$false

Links para a documentação relevante da Microsoft (para PowerShell 5.0; as versões 3.0 e 4.0 também estão disponíveis nos links):

ingênuos
fonte
58
De fato, uma das grandes vantagens do PowerShell é que ele fornece um parâmetro padrão de análise de infraestrutura que é fácil de usar.
Keith Hill
14
@naivists, do PowerShell 2.0 em vez de [string]$username = $(throw "-username is required.")há sintaxe para parâmetros obrigatórios: [Parameter(Mandatory=$true)][string]$username. Aqui está mais informações sobre a diferença entre estas técnicas: blogs.technet.com/b/heyscriptingguy/archive/2011/05/22/...
v.karbovnichy
7
Cuidado com o erro quando um argumento não é fornecido; o powershell irá apenas pegar qualquer texto extra na linha de comando:. \ YOURScript.PS1 -server " serv " -password "mypass" typo Isso irá atribuir magicamente 'typo' ao $ username.
sheamus
4
O uso de um bloco param parece ter outras conseqüências não intencionais: stackoverflow.com/questions/40940819/…
Logan
1
@ sheamus: isso não é um bug! O Powershell processará e atribuirá os argumentos na ordem em que são fornecidos, a menos que sejam substituídos usando o nome do parâmetro apropriado, por exemplo, se o seu bloco de parâmetros listar: $ user $ pass $ server e você executar o arquivocript.ps1 abc, a será definido em $ user, b em $ pass ec em $ server, a menos que você os atribua especificamente! Portanto, se você disser: yourscript.ps1 -pass abc, $ pass será definido como a e os demais parâmetros (sem nome) serão usados ​​para preencher os que estão faltando, na ordem listada no bloco de parâmetros, portanto, $ user = b, $ servidor = c.
Fernando Madruga