Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Tudo o que você queria saber sobre a declaração
Como muitas outras linguagens, o PowerShell tem instruções para executar condicionalmente o código em seus scripts. Uma dessas instruções é a instrução If. Hoje, vamos nos aprofundar em um dos comandos mais fundamentais do PowerShell.
Observação
A versão original deste artigo foi publicada no blog escrito por @KevinMarquette. A equipe do PowerShell agradece kevin por compartilhar este conteúdo conosco. Confira o blog dele no PowerShellExplained.com.
Execução condicional
Seus scripts geralmente precisam tomar decisões e executar uma lógica diferente com base nessas decisões.
Isso é o que quero dizer com execução condicional. Você tem uma instrução ou valor a ser avaliado e, em seguida, executa uma seção diferente do código com base nessa avaliação. Isso é exatamente o que a instrução if
faz.
A instrução if
Aqui está um exemplo básico da instrução if
:
$condition = $true
if ( $condition )
{
Write-Output "The condition was true"
}
A primeira coisa que a instrução if
faz é avaliar a expressão entre parênteses. Se for avaliada como $true
, executará o scriptblock
nas chaves. Se o valor fosse $false
, ele pularia esse bloco de scripts.
No exemplo anterior, a instrução if
estava apenas avaliando a variável $condition
. Foi $true
e teria executado o comando Write-Output
dentro do scriptblock.
Em alguns idiomas, você pode colocar uma única linha de código após a instrução if
e ela é executada. Esse não é o caso no PowerShell. Você deverá fornecer um scriptblock
completo com chaves para funcionar corretamente.
Operadores de comparação
O uso mais comum da instrução if
é comparar dois itens entre si. O PowerShell tem operadores especiais para diferentes cenários de comparação. Quando você usa um operador de comparação, o valor no lado esquerdo é comparado ao valor no lado direito.
-eq para igualdade
O -eq
faz uma verificação de igualdade entre dois valores para garantir que eles sejam iguais um ao outro.
$value = Get-MysteryValue
if ( 5 -eq $value )
{
# do something
}
Neste exemplo, estou pegando um valor conhecido de 5
e comparando-o ao meu $value
para ver se eles correspondem.
Um possível caso de uso é verificar o status de um valor antes de executar uma ação nele. Você pode obter um serviço e verificar se o status estava definido como em execução antes de chamar Restart-Service
.
É comum em outras linguagens, como C#, usar ==
para igualdade (por exemplo, 5 == $value
), mas isso não funciona com o PowerShell. Outro erro comum que as pessoas cometem é usar o sinal de igual (por exemplo: 5 = $value
) reservado para atribuir valores a variáveis. Ao colocar seu valor conhecido à esquerda, fica mais difícil cometer esse erro.
Este operador (e outros) tem algumas variações.
-
-eq
igualdade que não diferencia maiúsculas e minúsculas -
-ieq
igualdade que não diferencia maiúsculas e minúsculas -
-ceq
igualdade que diferencia maiúsculas e minúsculas
-ne diferente de
Muitos operadores têm um operador relacionado que está verificando o resultado oposto. -ne
verifica se os valores não são iguais uns aos outros.
if ( 5 -ne $value )
{
# do something
}
Use isso para garantir que a ação seja executada somente se o valor não for 5
. Um bom caso de uso seria verificar se um serviço estava em execução antes de tentar iniciá-lo.
Variações de :
-
-ne
não igualar maiúsculas de minúsculas -
-ine
não igualar maiúsculas de minúsculas -
-cne
não igualar diferenciação de maiúsculas de minúsculas
Estas são variações inversas de -eq
. Agruparei esses tipos ao listar variações para outros operadores.
-gt -ge -lt -le para maior que ou menor que
Esses operadores são usados ao verificar se um valor é maior ou menor que outro valor.
Os -gt -ge -lt -le
são GreaterThan, GreaterThanOrEqual, LessThan e LessThanOrEqual.
if ( $value -gt 5 )
{
# do something
}
Variações de :
-
-gt
maior que -
-igt
maior que, não diferencia maiúsculas de minúsculas -
-cgt
maior que, diferencia maiúsculas de minúsculas -
-ge
maior que ou igual a -
-ige
maior que ou igual a, não diferencia maiúsculas de minúsculas -
-cge
maior que ou igual a, diferencia maiúsculas de minúsculas -
-lt
menor que -
-ilt
menor que, não diferencia maiúsculas de minúsculas -
-clt
menor que, diferencia maiúsculas de minúsculas -
-le
menor que ou igual a -
-ile
menor que ou igual a, não diferencia maiúsculas de minúsculas -
-cle
menor que ou igual a, diferencia maiúsculas de minúsculas
Não sei por que você usaria opções que diferenciam e não diferenciam maiúsculas de minúsculas para esses operadores.
-like correspondências de caractere curinga
O PowerShell tem sua própria sintaxe de correspondência de padrões baseada em curinga e você pode usá-la com o operador -like
. Esses padrões de caractere curinga são bastante básicos.
?
corresponde a qualquer caractere único*
corresponde a qualquer número de caracteres
$value = 'S-ATX-SQL01'
if ( $value -like 'S-*-SQL??')
{
# do something
}
É importante ressaltar que o padrão corresponde à cadeia de caracteres inteira. Se você precisar corresponder a algo no meio da cadeia de caracteres, será necessário colocar o *
em ambas as extremidades da cadeia de caracteres.
$value = 'S-ATX-SQL02'
if ( $value -like '*SQL*')
{
# do something
}
Variações de :
-
-like
caractere curinga que não diferencia maiúsculas de minúsculas -
-ilike
caractere curinga que não diferencia maiúsculas de minúsculas -
-clike
caractere curinga que diferencia maiúsculas de minúsculas -
-notlike
caractere curinga que não diferencia maiúsculas e minúsculas não correspondente -
-inotlike
caractere curinga que não diferencia maiúsculas e minúsculas não correspondente -
-cnotlike
caractere curinga que diferencia maiúsculas e minúsculas não correspondente
-match expressão regular
O operador -match
permite que você verifique uma cadeia de caracteres para uma correspondência baseada em expressão regular. Use quando os padrões de caractere curinga não são flexíveis o suficiente.
$value = 'S-ATX-SQL01'
if ( $value -match 'S-\w\w\w-SQL\d\d')
{
# do something
}
Um padrão regex corresponde a qualquer lugar da cadeia de caracteres por padrão. Portanto, você pode especificar uma substring de caracteres que você deseja corresponder, por exemplo:
$value = 'S-ATX-SQL01'
if ( $value -match 'SQL')
{
# do something
}
Regex é uma linguagem complexa própria e vale a pena examinar. Falo mais sobre -match
e as várias maneiras de usar o regex em outro artigo.
Variações de :
-
-match
regex que não diferencia maiúsculas e minúsculas -
-imatch
regex que não diferencia maiúsculas e minúsculas -
-cmatch
regex que diferencia maiúsculas e minúsculas -
-notmatch
regex que não diferencia maiúsculas e minúsculas não correspondente -
-inotmatch
regex que não diferencia maiúsculas e minúsculas não correspondente -
-cnotmatch
regex que diferencia maiúsculas e minúsculas não correspondente
-is é tipo
Você pode verificar o tipo de um valor com o operador -is
.
if ( $value -is [string] )
{
# do something
}
Você pode usá-lo se estiver trabalhando com classes ou aceitando vários objetos por meio do pipeline. Você pode ter um serviço ou um nome de serviço como entrada. Verifique se você tem um serviço e busque-o apenas com o nome.
if ( $Service -isnot [System.ServiceProcess.ServiceController] )
{
$Service = Get-Service -Name $Service
}
Variações de :
-
-is
do tipo -
-isnot
não é do tipo
Operadores de coleção
Quando você usa os operadores anteriores com um único valor, o resultado é $true
ou $false
. Isso é tratado de forma ligeiramente diferente ao trabalhar com uma coleção. Cada item da coleção é avaliado e o operador retorna todos os valores que são avaliados como $true
.
PS> 1,2,3,4 -eq 3
3
Isso ainda funciona corretamente em uma instrução if
. Portanto, um valor é retornado pelo operador e, em seguida, toda a instrução é $true
.
$array = 1..6
if ( $array -gt 3 )
{
# do something
}
Há uma pequena armadilha escondida nos detalhes que preciso apontar. Ao usar o operador -ne
dessa forma, é fácil interpretar a lógica de forma invertida. Usar -ne
com uma coleção retornará $true
se qualquer item na coleção não corresponder ao seu valor.
PS> 1,2,3 -ne 4
1
2
3
Isso pode parecer um truque inteligente, mas temos operadores -contains
e -in
que lidam com isso com mais eficiência. E -notcontains
faz o que você espera.
-contains
O operador -contains
procura seu valor na coleção. Assim que encontra uma correspondência, retorna $true
.
$array = 1..6
if ( $array -contains 3 )
{
# do something
}
Essa é a maneira preferida de ver se uma coleção contém seu valor. O uso de Where-Object
(ou -eq
) percorre a lista inteira toda vez e é significativamente mais lento.
Variações de :
-
-contains
correspondência que não diferencia maiúsculas e minúsculas -
-icontains
correspondência que não diferencia maiúsculas e minúsculas -
-ccontains
correspondência que diferencia maiúsculas e minúsculas -
-notcontains
não correspondência que não diferencia maiúsculas e minúsculas -
-inotcontains
não correspondência que não diferencia maiúsculas e minúsculas -
-cnotcontains
não correspondência que diferencia maiúsculas e minúsculas
-in
O operador -in
é exatamente como o operador -contains
, exceto que a coleção está no lado direito.
$array = 1..6
if ( 3 -in $array )
{
# do something
}
Variações de :
-
-in
correspondência que não diferencia maiúsculas e minúsculas -
-iin
correspondência que não diferencia maiúsculas e minúsculas -
-cin
correspondência que diferencia maiúsculas e minúsculas -
-notin
não correspondência que não diferencia maiúsculas e minúsculas -
-inotin
não correspondência que não diferencia maiúsculas e minúsculas -
-cnotin
não correspondência que diferencia maiúsculas e minúsculas
Operadores lógicos
Operadores lógicos são usados para inverter ou combinar outras expressões.
-não
O operador -not
inverte uma expressão de $false
para $true
ou de $true
para $false
. Aqui está um exemplo em que queremos executar uma ação quando Test-Path
é $false
.
if ( -not ( Test-Path -Path $path ) )
A maioria dos operadores que falamos tem uma variação em que você não precisa usar o operador -not
. Mas ainda há momentos em que é útil.
! operador
Você pode usar !
como um alias para -not
.
if ( -not $value ){}
if ( !$value ){}
Você pode ver !
usado mais por pessoas familiarizadas com outras linguagens, como C#. Prefiro digitá-lo porque é difícil ver quando dou uma olhada rápida nos meus scripts.
-and
Você pode combinar expressões com o operador -and
. Quando você faz isso, ambos os lados precisam ser $true
para que toda a expressão seja $true
.
if ( ($age -gt 13) -and ($age -lt 55) )
Nesse exemplo, $age
deve ter 13 anos ou mais para o lado esquerdo e menos de 55 para o lado direito. Eu adicionei parênteses extras para deixar mais claro nesse exemplo, mas eles são opcionais desde que a expressão seja simples. Aqui está o mesmo exemplo sem eles.
if ( $age -gt 13 -and $age -lt 55 )
A avaliação ocorre da esquerda para a direita. Se o primeiro item for avaliado como $false
, ele sairá mais cedo e não executará a comparação correta. Isso é útil quando você precisa garantir que um valor exista antes de usá-lo. Por exemplo, Test-Path
gerará um erro se você lhe der um caminho $null
.
if ( $null -ne $path -and (Test-Path -Path $path) )
-or
O -or
permite que você especifique duas expressões e retorne $true
se uma delas for $true
.
if ( $age -le 13 -or $age -ge 55 )
Assim como acontece com o operador -and
, a avaliação ocorre da esquerda para a direita. Exceto que, se a primeira parte for $true
, a instrução inteira será $true
e não processará o restante da expressão.
Anote também como a sintaxe funciona para esses operadores. Você precisa de duas expressões separadas. Vi usuários tentarem fazer algo assim $value -eq 5 -or 6
sem perceber o erro.
-xor ou exclusivo
Este é um pouco incomum. -xor
permite que apenas uma expressão seja avaliada como $true
. Portanto, se ambos os itens forem $false
ou ambos os itens forem $true
, a expressão inteira será $false
. Outra maneira de analisar é que a expressão só será $true
quando os resultados da expressão forem diferentes.
É raro que alguém use esse operador lógico e não consigo pensar em um bom exemplo de por que eu o usaria.
Operadores bit a bit
Os operadores bit a bit executam cálculos nos bits dentro dos valores e produzem um novo valor como resultado. Ensinar operadores bit a bit está além do escopo deste artigo. Mas aqui está a lista deles.
-
-band
binário E -
-bor
binário OU -
-bxor
binário OR exclusivo -
-bnot
binário NÃO -
-shl
shift left -
-shr
shift right
Expressões do PowerShell
Podemos usar o PowerShell normal dentro da declaração condicional.
if ( Test-Path -Path $Path )
Test-Path
retorna $true
ou $false
quando é executado. Isso também se aplica a comandos que retornam outros valores.
if ( Get-Process Notepad* )
Será avaliado como $true
se houver um processo retornado e $false
se não houver um processo. É perfeitamente válido usar expressões de pipeline ou outras instruções do PowerShell como esta:
if ( Get-Process | where Name -EQ Notepad )
Essas expressões podem ser combinadas entre si com os operadores -and
e -or
, mas talvez seja necessário usar parênteses para dividi-las em subexpressões.
if ( (Get-Process) -and (Get-Service) )
Verificando se corresponde a $null
Obter "sem resultados" ou um valor de $null
é avaliado como $false
na instrução if
. Quando você verifica especificamente por $null
, é uma melhor prática adicionar $null
no lado esquerdo.
if ( $null -eq $value )
Há algumas nuances ao lidar com valores $null
no PowerShell. Se você está interessado em mergulhar mais fundo, eu tenho um artigo sobre tudo o que você queria saber sobre $null.
Atribuição de variável dentro da condição
Eu quase esqueci de adicionar isso até que Prasoon Karunan V me lembrou.
if ($process=Get-Process notepad -ErrorAction Ignore) {$process} else {$false}
Normalmente, quando você atribui um valor a uma variável, o valor não é passado para o pipeline ou console. Quando você faz uma atribuição de variável em uma subexpressão, ela é passada para o pipeline.
PS> $first = 1
PS> ($second = 2)
2
Confira como a atribuição de $first
não tem saída e a atribuição de $second
tem. Quando uma atribuição é feita em uma instrução if
, ela é executada da mesma forma que a atribuição de $second
acima. Aqui está um exemplo limpo sobre como você poderia usá-lo:
if ( $process = Get-Process Notepad* )
{
$process | Stop-Process
}
Se $process
receber um valor, a instrução será $true
e $process
será interrompida.
Certifique-se de não confundir isso com -eq
porque essa não é uma verificação de igualdade. Esse é um recurso mais obscuro que a maioria das pessoas não percebe que funciona assim.
Atribuição de variável do bloco de script
Você também pode usar o bloco de script de instrução if
para atribuir um valor a uma variável.
$discount = if ( $age -ge 55 )
{
Get-SeniorDiscount
}
elseif ( $age -le 13 )
{
Get-ChildDiscount
}
else
{
0.00
}
Cada bloco de script está gravando os resultados dos comandos ou o valor como saída. Podemos atribuir o resultado da instrução if
à variável $discount
. Esse exemplo poderia ter atribuído facilmente esses valores à variável $discount
diretamente em cada scriptblock. Não posso dizer que uso isso com a instrução if
com frequência, mas tenho um exemplo em que usei isso recentemente.
Caminho de execução alternativo
A instrução if
permite que você especifique uma ação não apenas para quando a instrução for $true
, mas também para quando for $false
. É aí que a instrução else
entra em cena.
else
A instrução else
é sempre a última parte da instrução if
quando usada.
if ( Test-Path -Path $Path -PathType Leaf )
{
Move-Item -Path $Path -Destination $archivePath
}
else
{
Write-Warning "$path doesn't exist or isn't a file."
}
Neste exemplo, verificamos a $path
para verificar se é um arquivo. Se encontrarmos o arquivo, o moveremos. Caso contrário, escreveremos um aviso. Esse tipo de lógica de ramificação é muito comum.
if aninhado
As instruções if
e else
tomam um bloco de script, para que possamos colocar qualquer comando do PowerShell dentro delas, incluindo outra instrução if
. Isso permite que você use uma lógica muito mais complicada.
if ( Test-Path -Path $Path -PathType Leaf )
{
Move-Item -Path $Path -Destination $archivePath
}
else
{
if ( Test-Path -Path $Path )
{
Write-Warning "A file was required but a directory was found instead."
}
else
{
Write-Warning "$path could not be found."
}
}
Neste exemplo, testamos o caminho feliz primeiro e, em seguida, tomamos medidas sobre ele. Se isso falhar, faremos outra verificação e forneceremos informações mais detalhadas ao usuário.
elseif
Não estamos limitados a apenas uma única verificação condicional. Podemos encadear instruções if
e else
juntas em vez de aninhar usando a instrução elseif
.
if ( Test-Path -Path $Path -PathType Leaf )
{
Move-Item -Path $Path -Destination $archivePath
}
elseif ( Test-Path -Path $Path )
{
Write-Warning "A file was required but a directory was found instead."
}
else
{
Write-Warning "$path could not be found."
}
A execução ocorre de cima para baixo. A instrução if
superior é avaliada primeiro. Se for $false
, passará para a próxima elseif
ou else
na lista. Essa última else
é a ação padrão a ser tomada se nenhuma das outras retornar $true
.
switch
Neste ponto, preciso mencionar a declaração switch
. Ele fornece uma sintaxe alternativa para fazer várias comparações com um valor. Com o switch
, você especifica uma expressão e esse resultado é comparado com vários valores diferentes. Se um desses valores corresponder, o bloco de código correspondente será executado. Dê uma olhada neste exemplo:
$itemType = 'Role'
switch ( $itemType )
{
'Component'
{
'is a component'
}
'Role'
{
'is a role'
}
'Location'
{
'is a location'
}
}
Há três valores possíveis que podem corresponder ao $itemType
. Nesse caso, ele corresponde ao Role
. Eu usei um exemplo simples apenas para lhe dar um pouco de familiaridade com o operador switch
. Falarei mais sobre tudo o que você queria saber sobre a instrução switch em outro artigo.
Matriz embutida
Tenho uma função chamada Invoke-SnowSql que inicia um executável com vários argumentos de linha de comando. Aqui está um clipe dessa função em que eu compilo a matriz de argumentos.
$snowSqlParam = @(
'--accountname', $Endpoint
'--username', $Credential.UserName
'--option', 'exit_on_error=true'
'--option', 'output_format=csv'
'--option', 'friendly=false'
'--option', 'timing=false'
if ($Debug)
{
'--option', 'log_level=DEBUG'
}
if ($Path)
{
'--filename', $Path
}
else
{
'--query', $singleLineQuery
}
)
As variáveis $Debug
e $Path
são parâmetros na função fornecida pelo usuário final.
Posso avaliar embutidos dentro da inicialização da minha matriz. Se $Debug
for verdadeiro, esses valores serão inseridos no $snowSqlParam
no lugar correto. O mesmo vale para a variável $Path
.
Simplificar operações complexas
É inevitável enfrentar situações em que haja muitas comparações a serem verificadas e a instrução if
fique na extremidade direita da tela.
$user = Get-ADUser -Identity $UserName
if ( $null -ne $user -and $user.Department -eq 'Finance' -and $user.Title -match 'Senior' -and $user.HomeDrive -notlike '\\server\*' )
{
# Do Something
}
Eles podem ser difíceis de ler e isso te tornam mais propenso a cometer erros. Há algumas coisas que podemos fazer sobre isso.
Continuação de linha
Há alguns operadores no PowerShell que permitem encapsular o comando para a próxima linha. Os operadores lógicos -and
e -or
são bons operadores a serem usados se você quiser dividir sua expressão em várias linhas.
if ($null -ne $user -and
$user.Department -eq 'Finance' -and
$user.Title -match 'Senior' -and
$user.HomeDrive -notlike '\\server\*'
)
{
# Do Something
}
Ainda há muita coisa acontecendo, mas colocar cada peça em sua própria linha faz uma grande diferença. Geralmente uso isso quando recebo mais de duas comparações ou se tenho que rolar para a direita para ler qualquer uma das lógicas.
Resultados de pré-cálculo
Podemos retirar essa declaração da instrução if
e verificar apenas o resultado.
$needsSecureHomeDrive = $null -ne $user -and
$user.Department -eq 'Finance' -and
$user.Title -match 'Senior' -and
$user.HomeDrive -notlike '\\server\*'
if ( $needsSecureHomeDrive )
{
# Do Something
}
Isso parece muito mais limpo do que o exemplo anterior. Você também tem a oportunidade de usar um nome de variável que explica o que é que você está realmente verificando. Este também é um exemplo de código de auto-documentação que salva comentários desnecessários.
Várias instruções if
Podemos dividir isso em várias afirmações e verificá-las uma de cada vez. Nesse caso, usamos um sinalizador ou uma variável de acompanhamento para combinar os resultados.
$skipUser = $false
if( $null -eq $user )
{
$skipUser = $true
}
if( $user.Department -ne 'Finance' )
{
Write-Verbose "isn't in Finance department"
$skipUser = $true
}
if( $user.Title -match 'Senior' )
{
Write-Verbose "Doesn't have Senior title"
$skipUser = $true
}
if( $user.HomeDrive -like '\\server\*' )
{
Write-Verbose "Home drive already configured"
$skipUser = $true
}
if ( -not $skipUser )
{
# do something
}
Eu tive que inverter a lógica para fazer a lógica de bandeira funcionar corretamente. Cada avaliação é uma instrução if
individual. A vantagem disso é que, quando você estiver depurando, poderá dizer exatamente o que a lógica está fazendo. Ao mesmo tempo, consegui adicionar um detalhamento muito melhor.
A desvantagem óbvia é que é muito mais código para escrever. O código é mais complexo de examinar, pois ele usa uma única linha de lógica e o explode em 25 ou mais linhas.
Usar funções
Também podemos mover toda essa lógica de validação para uma função. Veja como isso parece limpo à primeira vista.
if ( Test-SecureDriveConfiguration -ADUser $user )
{
# do something
}
Você ainda precisa criar a função para fazer a validação, mas isso torna esse código muito mais fácil de trabalhar. Isso facilita o teste desse código. Nos seus testes, você pode simular a chamada para Test-ADDriveConfiguration
e precisa de apenas dois testes para essa função. Um em que retorna $true
e outro em que retorna $false
. Testar a outra função é mais simples porque ela é tão pequena.
O corpo dessa função ainda pode ser aquela linha única com a qual começamos ou a lógica expandida que usamos na última seção. Isso funciona bem para ambos os cenários e permite que você altere facilmente essa implementação mais tarde.
Tratamento de erros
Um uso importante da instrução if
é verificar se há condições de erro antes de ocorrerem erros. Um bom exemplo é verificar se uma pasta já existe antes de você tentar criá-la.
if ( -not (Test-Path -Path $folder) )
{
New-Item -Type Directory -Path $folder
}
Eu gosto de dizer que se você espera que uma exceção aconteça, então não é realmente uma exceção. Portanto, verifique seus valores e valide suas condições onde puder.
Se você quiser se aprofundar um pouco mais no manejo de exceções de forma prática, tenho um artigo sobre tudo o que você sempre quis saber a respeito de exceções.
Palavras finais
A instrução if
é uma instrução simples, mas é uma parte fundamental do PowerShell. Você se verá usando isso várias vezes em quase todos os scripts que você escreve. Espero que tenha uma compreensão melhor do que tinha antes.