Tudo o que você queria saber sobre a if
declaração
Como muitas outras linguagens, o PowerShell tem instruções para executar condicionalmente código em seus scripts. Uma dessas afirmações é a declaração If . Hoje vamos dar um mergulho profundo em um dos comandos mais fundamentais do PowerShell.
Nota
A versão original deste artigo apareceu no blog escrito por @KevinMarquette. A equipe do PowerShell agradece Kevin por compartilhar esse conteúdo conosco. Por favor, confira seu blog em PowerShellExplained.com.
Execução condicional
Seus scripts geralmente precisam tomar decisões e executar lógicas diferentes com base nessas decisões.
É isto que quero dizer com execução condicional. Você tem uma instrução ou valor para avaliar e, em seguida, executar uma seção diferente de código com base nessa avaliação. É exatamente isso que a if
declaração faz.
A if
declaração
Aqui está um exemplo básico da if
afirmação:
$condition = $true
if ( $condition )
{
Write-Output "The condition was true"
}
A primeira coisa que o enunciado if
faz é avaliar a expressão entre parênteses. Se ele avalia para $true
, então ele executa o scriptblock
nos chaves. Se o valor fosse $false
, ele ignoraria esse scriptblock.
No exemplo anterior, a if
afirmação era apenas avaliar a $condition
variável. $true
Foi e teria executado o Write-Output
comando dentro do scriptblock.
Em alguns idiomas, você pode colocar uma única linha de código após a if
instrução e ela é executada. Esse não é o caso no PowerShell. Você deve fornecer um completo scriptblock
com chaves para que ele funcione corretamente.
Operadores de comparação
O uso mais comum da if
declaração para é 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 com o valor no lado direito.
-QE para a igualdade
O -eq
faz uma verificação de igualdade entre dois valores para se certificar de que eles são iguais um ao outro.
$value = Get-MysteryValue
if ( 5 -eq $value )
{
# do something
}
Neste exemplo, estou pegando um valor conhecido e 5
comparando-o com o meu $value
para ver se eles correspondem.
Um caso de uso possível é verificar o status de um valor antes de executar uma ação sobre ele. Você pode obter um serviço e verificar se o status estava em execução antes de chamá-lo 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 (ex: 5 = $value
) que é reservado para atribuir valores a variáveis. Ao colocar o seu valor conhecido à esquerda, torna esse erro mais difícil de cometer.
Este operador (e outros) tem algumas variações.
-eq
Igualdade insensível a maiúsculas e minúsculas-ieq
Igualdade insensível a maiúsculas e minúsculas-ceq
igualdade sensível a maiúsculas e minúsculas
-ne não igual
Muitos operadores têm um operador relacionado que está verificando o resultado oposto. -ne
verifica se os valores não são iguais.
if ( 5 -ne $value )
{
# do something
}
Use isso para garantir que a ação só seja executada se o valor não 5
for . Um bom caso de uso seria verificar se um serviço estava no estado de execução antes de tentar iniciá-lo.
Variações:
-ne
insensível a maiúsculas e minúsculas não igual-ine
insensível a maiúsculas e minúsculas não igual-cne
sensível a maiúsculas e minúsculas não igual
Estas são variações inversas de -eq
. Agruparei esses tipos quando listar variações para outros operadores.
-gt -ge -lt -le para maior ou menor que
Esses operadores são usados ao verificar se um valor é maior ou menor do que outro valor.
O -gt -ge -lt -le
significa GreaterThan, GreaterThanOrEqual, LessThan e LessThanOrEqual.
if ( $value -gt 5 )
{
# do something
}
Variações:
-gt
superior a-igt
maior que, sem diferenciação de maiúsculas e minúsculas-cgt
maior que, sensível a maiúsculas e minúsculas-ge
maior ou igual-ige
maior ou igual, sem diferenciação de maiúsculas e minúsculas-cge
maior ou igual, sensível a maiúsculas e minúsculas-lt
menos de-ilt
menos do que, sem distinção entre maiúsculas e minúsculas-clt
menos do que, sensível a maiúsculas e minúsculas-le
menor ou igual-ile
menor ou igual, sem diferenciação de maiúsculas e minúsculas-cle
menor ou igual, sensível a maiúsculas e minúsculas
Não sei por que você usaria opções que diferenciam maiúsculas de minúsculas e insensíveis para esses operadores.
-como partidas curinga
O PowerShell tem sua própria sintaxe de correspondência de padrão baseada em curinga e você pode usá-la com o -like
operador. Esses padrões curinga são bastante básicos.
?
corresponde a qualquer caractere*
corresponde a qualquer número de caracteres
$value = 'S-ATX-SQL01'
if ( $value -like 'S-*-SQL??')
{
# do something
}
É importante salientar que o padrão corresponde a toda a string. Se você precisar combinar algo no meio da string, você precisa colocar o *
em ambas as extremidades da string.
$value = 'S-ATX-SQL02'
if ( $value -like '*SQL*')
{
# do something
}
Variações:
-like
Curinga que não diferencia maiúsculas de minúsculas-ilike
Curinga que não diferencia maiúsculas de minúsculas-clike
Curinga que diferencia maiúsculas de minúsculas-notlike
Curinga que não diferencia maiúsculas de minúsculas não correspondido-inotlike
Curinga que não diferencia maiúsculas de minúsculas não correspondido-cnotlike
Curinga que diferencia maiúsculas de minúsculas não correspondido
-corresponder expressão regular
O -match
operador permite que você verifique uma cadeia de caracteres para uma correspondência baseada em expressão regular. Use isso quando os padrões curinga não forem flexíveis o suficiente para você.
$value = 'S-ATX-SQL01'
if ( $value -match 'S-\w\w\w-SQL\d\d')
{
# do something
}
Um padrão regex corresponde a qualquer lugar na cadeia de caracteres por padrão. Assim, você pode especificar uma substring que deseja corresponder da seguinte forma:
$value = 'S-ATX-SQL01'
if ( $value -match 'SQL')
{
# do something
}
Regex é uma linguagem complexa por si só e vale a pena investigar. Eu falo mais sobre -match
e as muitas maneiras de usar regex em outro artigo.
Variações:
-match
regex que não diferencia maiúsculas de minúsculas-imatch
regex que não diferencia maiúsculas de minúsculas-cmatch
regex sensível a maiúsculas e minúsculas-notmatch
regex que não diferencia maiúsculas de minúsculas não correspondido-inotmatch
regex que não diferencia maiúsculas de minúsculas não correspondido-cnotmatch
regex sensível a maiúsculas e minúsculas não correspondido
-é do tipo
Você pode verificar o tipo de um valor com o -is
operador.
if ( $value -is [string] )
{
# do something
}
Você pode usar isso se estiver trabalhando com classes ou aceitando vários objetos ao longo do pipeline. Você pode ter um serviço ou um nome de serviço como sua entrada. Em seguida, verifique se você tem um serviço e busque o serviço se você tiver apenas o nome.
if ( $Service -isnot [System.ServiceProcess.ServiceController] )
{
$Service = Get-Service -Name $Service
}
Variações:
-is
do tipo-isnot
não do tipo
Operadores de recolha
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 cada valor avaliado para $true
.
PS> 1,2,3,4 -eq 3
3
Isso ainda funciona corretamente em uma if
declaração. Assim, um valor é devolvido pelo seu operador, então toda a instrução é $true
.
$array = 1..6
if ( $array -gt 3 )
{
# do something
}
Há uma pequena armadilha escondida nos detalhes aqui que eu preciso apontar. Ao usar o -ne
operador dessa forma, é fácil olhar erroneamente para a lógica de trás para frente. Usar -ne
com uma coleção retorna $true
se algum item da 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
-in
que lidam com isso de forma mais eficiente. E -notcontains
faz o que espera.
-contém
O -contains
operador verifica a cobrança quanto ao seu valor. Assim que encontrar uma correspondência, ele retorna $true
.
$array = 1..6
if ( $array -contains 3 )
{
# do something
}
Esta é a maneira preferida de ver se uma coleção contém o seu valor. Usar Where-Object
(ou -eq
) percorre toda a lista todas as vezes e é significativamente mais lento.
Variações:
-contains
correspondência que não diferencia maiúsculas de minúsculas-icontains
correspondência que não diferencia maiúsculas de minúsculas-ccontains
correspondência que diferencia maiúsculas de minúscul-notcontains
insensível a maiúsculas e minúsculas não correspondido-inotcontains
insensível a maiúsculas e minúsculas não correspondido-cnotcontains
sensível a maiúsculas e minúsculas não correspondido
-em
O -in
operador é como o operador, -contains
exceto que a coleta está no lado direito.
$array = 1..6
if ( 3 -in $array )
{
# do something
}
Variações:
-in
correspondência que não diferencia maiúsculas de minúsculas-iin
correspondência que não diferencia maiúsculas de minúsculas-cin
correspondência que diferencia maiúsculas de minúscul-notin
insensível a maiúsculas e minúsculas não correspondido-inotin
insensível a maiúsculas e minúsculas não correspondido-cnotin
sensível a maiúsculas e minúsculas não correspondido
Operadores lógicos
Os operadores lógicos são usados para inverter ou combinar outras expressões.
-não
O -not
operador inverte uma expressão de $false
para $true
ou de $true
para $false
. Aqui está um exemplo onde queremos executar uma ação quando Test-Path
é $false
.
if ( -not ( Test-Path -Path $path ) )
A maioria dos operadores de que falamos tem uma variação em que você não precisa usar o -not
operador. Mas ainda há momentos em que é útil.
! operador
Você pode usar !
como um alias para -not
.
if ( -not $value ){}
if ( !$value ){}
Você pode ver !
mais usado por pessoas que vêm de outras linguagens como C#. Eu prefiro digitá-lo porque acho difícil de ver quando olho rapidamente para meus scripts.
-e
Você pode combinar expressões com o -and
operador. 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 acontece da esquerda para a direita. Se o primeiro item for avaliado como $false
, ele sai cedo e não realiza a comparação correta. Isso é útil quando você precisa se certificar de que um valor existe antes de usá-lo. Por exemplo, Test-Path
lança um erro se você lhe der um $null
caminho.
if ( $null -ne $path -and (Test-Path -Path $path) )
-ou
O -or
permite que você especifique duas expressões e retorna $true
se qualquer uma delas for $true
.
if ( $age -le 13 -or $age -ge 55 )
Tal como acontece com o -and
operador, a avaliação acontece da esquerda para a direita. Só que se a primeira parte é $true
, então toda a instrução é $true
e não processa o resto da expressão.
Anote também como a sintaxe funciona para esses operadores. Você precisa de duas expressões separadas. Eu vi usuários tentarem fazer algo assim $value -eq 5 -or 6
sem perceber seu erro.
-xor exclusivo ou
Este é um pouco incomum. -xor
permite que apenas uma expressão seja avaliada a $true
. Portanto, se ambos os itens são $false
ou ambos os itens são $true
, então toda a expressão é $false
. Outra maneira de olhar para isso é a expressão é apenas $true
quando os resultados da expressão são diferentes.
É raro alguém usar esse operador lógico e eu não consigo pensar em um bom exemplo de por que eu o usaria.
Operadores bit-a-bit
Os operadores Bitwise executam cálculos nos bits dentro dos valores e produzem um novo valor como resultado. Ensinar operadores bitwise está além do escopo deste artigo, mas aqui está a lista deles.
-band
binário E-bor
binário OU-bxor
binário exclusivo OU-bnot
binário NÃO-shl
Vire para a esquerda-shr
Vire para a direita
Expressões do PowerShell
Podemos usar o PowerShell normal dentro da instrução de condição.
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* )
Ele avalia se $true
há um processo devolvido e $false
se não há. É 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 -and
operadores e -or
, mas você pode ter que usar parênteses para dividi-las em subexpressões.
if ( (Get-Process) -and (Get-Service) )
Verificando se há $null
Ter um resultado ou um $null
valor não é $false
avaliado na if
declaração. Ao verificar especificamente o $null
, é uma prática recomendada colocar o $null
no lado esquerdo.
if ( $null -eq $value )
Há algumas nuances ao lidar com $null
valores 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 variável dentro da condição
Eu quase esqueci de adicionar este até que Prasoon Karunan V me lembrou disso.
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
Viu como a $first
atribuição não tem saída e a $second
atribuição tem? Quando uma atribuição é feita em uma if
instrução, ela é executada exatamente como a $second
atribuição acima. Aqui está um exemplo limpo sobre como você poderia usá-lo:
if ( $process = Get-Process Notepad* )
{
$process | Stop-Process
}
Se $process
for atribuído um valor, então a instrução é $true
e $process
é interrompida.
Certifique-se de não confundir isso com -eq
porque isso não é uma verificação de igualdade. Esta é uma característica mais obscura que a maioria das pessoas não percebe que funciona desta forma.
Atribuição variável do scriptblock
Você também pode usar a if
instrução scriptblock 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 if
instrução à $discount
variável. Esse exemplo poderia ter facilmente atribuído esses valores à $discount
variável diretamente em cada bloco de script. Não posso dizer que uso isso com a declaração com frequência if
, mas tenho um exemplo em que usei isso recentemente.
Caminho de execução alternativo
A if
instrução permite que você especifique uma ação não apenas para quando a instrução é $true
, mas também para quando é $false
. É aqui que entra em jogo a else
declaração.
else
A else
instrução é sempre a última parte da if
declaração 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 se é $path
um arquivo. Se encontrarmos o ficheiro, movemo-lo. Se não, escrevemos um aviso. Este tipo de lógica de ramificação é muito comum.
Aninhado se
As if
instruções e else
usam um bloco de script, para que possamos colocar qualquer comando do PowerShell dentro delas, incluindo outra if
instrução. Isso permite que você faça uso de 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 primeiro o caminho feliz e, em seguida, agimos sobre ele. Se isso falhar, fazemos outra verificação e fornecemos informações mais detalhadas ao usuário.
elseif
Não estamos limitados a apenas uma única verificação condicional. Podemos encadear if
e else
agrupar instruções em vez de aninha-las usando a elseif
instrução.
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 acontece de cima para baixo. A declaração superior if
é avaliada primeiro. Se for $false
, então ele passa para o próximo 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 switch
declaração. 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. Veja este 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
. Neste caso, corresponde ao Role
. Eu usei um exemplo simples apenas para lhe dar alguma exposição ao switch
operador. Eu falo mais sobre tudo o que você sempre quis saber sobre a declaração de mudança em outro artigo.
Array em linha
Eu 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 onde eu construo 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 $Debug
variáveis e $Path
são parâmetros na função que são fornecidos pelo usuário final.
Eu os avalio em linha dentro da inicialização da minha matriz. Se $Debug
for verdade, então esses valores caem $snowSqlParam
no lugar correto. O mesmo vale para a $Path
variável.
Simplifique operações complexas
É inevitável que você se depare com uma situação que tem muitas comparações para verificar e sua If
declaração rola para fora do lado direito 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 que o tornam mais propenso a cometer erros. Há algumas coisas que podemos fazer a esse respeito.
Continuação da linha
Há alguns operadores no PowerShell que permitem que você envolva seu comando para a próxima linha. Os operadores -and
lógicos e -or
são bons operadores para usar 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 por lá, mas colocar cada peça em sua própria linha faz uma grande diferença. Eu 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.
Pré-cálculo dos resultados
Podemos retirar essa declaração da if
declaração e apenas verificar 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 você está realmente verificando. Este também é um exemplo de código de auto-documentação que salva comentários desnecessários.
Múltiplas instruções if
Podemos dividir isso em várias declarações e verificá-las uma de cada vez. Neste caso, usamos um sinalizador ou uma variável de rastreamento 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 da bandeira funcionar corretamente. Cada avaliação é uma declaração individual if
. A vantagem disso é que, quando você está depurando, você pode dizer exatamente o que a lógica está fazendo. Eu fui capaz de adicionar muito melhor verbosidade ao mesmo tempo.
A desvantagem óbvia é que é muito mais código para escrever. O código é mais complexo de observar, pois pega uma única linha de lógica e a explode em 25 ou mais linhas.
Usando funções
Também podemos mover toda essa lógica de validação para uma função. Olhe para o quão limpo isso parece em um piscar de olhos.
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 torna esse código mais fácil de testar. Em seus testes, você pode simular a chamada para Test-ADDriveConfiguration
e você só precisa de dois testes para esta função. Um onde regressa $true
e outro onde regressa $false
. Testar a outra função é mais simples porque é muito pequena.
O corpo dessa função ainda pode ser aquele one-liner com o qual começamos ou a lógica explodida 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.
Processamento de erros
Um uso importante da instrução é verificar se if
há condições de erro antes de encontrar erros. Um bom exemplo é verificar se uma pasta já existe antes de 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. Por isso, verifique os seus valores e valide as suas condições sempre que possível.
Se você quiser mergulhar um pouco mais no tratamento real de exceções, tenho um artigo sobre tudo o que você sempre quis saber sobre exceções.
Palavras finais
A if
declaração é tão simples, mas é uma peça fundamental do PowerShell. Você vai se encontrar usando isso várias vezes em quase todos os scripts que você escreve. Espero que tenha uma melhor compreensão do que tinha antes.
Comentários
https://aka.ms/ContentUserFeedback.
Brevemente: Ao longo de 2024, vamos descontinuar progressivamente o GitHub Issues como mecanismo de feedback para conteúdos e substituí-lo por um novo sistema de feedback. Para obter mais informações, veja:Submeter e ver comentários