PowerShell – Operatori e condizioni

Finora abbiamo eseguito i comandi uno dopo l’altro, senza mai fermarci a pensare. Per rendere uno script davvero utile dobbiamo insegnargli a prendere decisioni: fare una cosa se il file esiste e un’altra se non esiste, trattare in modo diverso un PDF e una foto, ignorare i file più vecchi di 30 giorni.

Avete già letto le mie guide PowerShell – Introduzione e PowerShell – Gestione del File System?

In PowerShell le decisioni funzionano in due tempi. Gli operatori di confronto, come -eq e -like, valutano una condizione e restituiscono True o False. I costrutti if e switch agiscono poi su quel risultato, decidendo quale blocco di codice eseguire.

Prepariamo una cartella di prova

Come sempre, prima di sperimentare creiamo una cartella di test: gli esempi di questo capitolo useranno sei file con dimensioni e date di modifica diverse, così avremo qualcosa su cui confrontare e decidere. Copiate ed eseguite questo blocco (le date di modifica le “falsifichiamo” con LastWriteTime):

NOTA: usiamo Join-Path $PWD perché i metodi .NET come [System.IO.File]::Create risolvono i percorsi relativi partendo dalla cartella in cui è stato avviato il processo, non da quella in cui ci siamo spostati con Set-Location. Il suffisso KB, MB e GB è invece un comodo “zucchero” di PowerShell: 3MB vale 3145728.

Verifichiamo cosa abbiamo creato:

Figura 1: la cartella di prova

Operatori di confronto

Un operatore di confronto mette a confronto due valori e restituisce sempre un valore booleano: True oppure False. Chi arriva da altri linguaggi cercherà ==, > e <, ma in PowerShell non funzionano come ci si aspetta: = serve per assegnare un valore e > per redirigere l’output su un file. Per questo gli operatori di confronto iniziano con un trattino e sono abbreviazioni inglesi (equal, greater than, less than, …).

Confrontare numeri e valori: -eq, -ne, -gt, -ge, -lt, -le

Operatore Significato Esempio
-eq Uguale a (equal) 5 -eq 5
-ne Diverso da (not equal) 5 -ne 3
-gt Maggiore di (greater than) 10 -gt 3
-ge Maggiore o uguale (greater or equal) 10 -ge 10
-lt Minore di (less than) 2 -lt 5
-le Minore o uguale (less or equal) 2 -le 2

Come i nomi dei cmdlet, anche gli operatori non sono case sensitive: “PowerShell” -eq “powershell” è vero. Se la differenza tra maiuscole e minuscole conta basta anteporre una c all’operatore (-ceq, -cne, -clike, -cmatch, …); con una i si dichiara esplicitamente il comportamento di default (-ieq).

Figura 2: operatori di confronto numerici e case sensitivity

Confrontare testo: -like, -notlike, -match, -notmatch

Per il testo abbiamo due famiglie di operatori. Gli operatori -like e -notlike usano i caratteri jolly che conosciamo dal file system: * sostituisce un numero qualsiasi di caratteri, ? un carattere solo. Gli operatori -match e -notmatch usano invece le espressioni regolari (regex), molto più potenti. Con -match, quando la ricerca ha successo, PowerShell salva il testo trovato nella variabile automatica $Matches.

Operatore Significato Esempio
-like Corrisponde al carattere jolly “a.txt” -like “*.txt”
-notlike Non corrisponde al jolly “a.txt” -notlike “*.pdf”
-match Corrisponde alla regex “2026-03” -match “\d{4}”
-notmatch Non corrisponde alla regex “abc” -notmatch “\d”

Figura 3: -like, -notlike e -match

Appartenenza a una collezione: -contains, -in

Per sapere se un valore compare in un elenco usiamo -contains (con la collezione a sinistra) oppure -in (con il valore a sinistra): dicono la stessa cosa, cambia solo l’ordine dei termini, e -in si legge spesso più naturalmente. Esistono anche le versioni negate -notcontains e -notin.

Figura 4: -contains, -in e -notin

Quando a sinistra c’è un array

Qui PowerShell ci riserva una sorpresa. Se a sinistra di un operatore di confronto c’è una collezione (e non un singolo valore), l’operatore non restituisce True o False: funziona da filtro e restituisce gli elementi che soddisfano la condizione.

Figura 5: confronto con un array a sinistra: restituisce gli elementi

Attenzione: se volete sapere se un valore è presente in un elenco non usate -eq: usate -contains o -in, che restituiscono davvero True o False. Con -eq su un array un if può darvi la risposta sbagliata: if (@(1,0,2) -eq 0) risulta falso anche se lo 0 nell’elenco c’è, perché il filtro restituisce proprio 0, e 0 viene valutato come falso.

Operatori logici: -and, -or, -not, -xor

Quando una decisione dipende da più condizioni, gli operatori logici le combinano. Ogni condizione va racchiusa tra parentesi tonde, per evitare ambiguità e per rendere il codice leggibile.

Operatore Significato Esempio
-and Vero se entrambe sono vere ($a -gt 1) -and ($a -lt 9)
-or Vero se almeno una è vera ($a -lt 1) -or ($a -gt 9)
-not oppure ! Inverte il risultato -not ($a -eq 5)
-xor Vero se solo una è vera $true -xor $false

Figura 6: operatori logici

Nell’ultimo esempio si vede il corto circuito: se il primo termine di un -and è già False il risultato non può più cambiare, quindi PowerShell non valuta nemmeno il secondo e la scritta “non lo vedrai mai” non compare. Lo stesso vale per -or quando il primo termine è True.

La condizione if

Sintassi: if, elseif, else

Il costrutto if valuta una condizione tra parentesi tonde: se è vera esegue il blocco tra graffe, altrimenti passa all’eventuale elseif successivo e, se nessuno è vero, a else. I blocchi elseif e else sono facoltativi e elseif può essere ripetuto quante volte serve.

Sintassi:

Mettiamolo alla prova con la cartella di test. Il primo esempio usa

(visto nel capitolo sul file system), il secondo decide in base alla dimensione di un file:

Figura 7: if, elseif ed else

NOTA: le condizioni di un elseif vengono valutate in ordine e PowerShell si ferma alla prima vera. Per questo nell’esempio il controllo -gt 10MB viene prima di -gt 1MB: a parti invertite, una foto da 12 MB verrebbe classificata nel ramo sbagliato.

Cosa è vero e cosa è falso

La condizione di un if non deve per forza essere un confronto: PowerShell converte qualsiasi valore in booleano. Ecco i casi più comuni:

Valore Viene valutato come
0 False
qualsiasi numero diverso da 0 True
“” (stringa vuota) False
“testo” (stringa non vuota) True
“0” (stringa non vuota!) True
$null False
@() (array vuoto) False

Figura 8: conversione in booleano

Attenzione al terzo caso: la stringa “0” è vera, perché è una stringa non vuota, mentre il numero 0 è falso.

L’errore classico: = al posto di -eq

Attenzione: in un if, scrivere = al posto di -eq non dà errore: assegna il valore alla variabile, e il risultato dell’assegnazione (che è quasi sempre “vero”) diventa la condizione.

Figura 9: if ($x = 5) assegna invece di confrontare

La condizione è risultata vera e, peggio, la variabile $x ora vale 5. La forma corretta è if ($x -eq 5).

Scegliere tra molti valori: switch

Quando dobbiamo confrontare lo stesso valore con molte alternative una lunga catena di elseif diventa illeggibile. Il costrutto switch risolve il problema: valuta un’espressione ed esegue il blocco della prima (o di tutte) le alternative che corrispondono. Il ramo default viene eseguito se nessuna alternativa corrisponde.

Sintassi:

Figura 10: switch su un valore

Più rami possono scattare: break

differenza di molti altri linguaggi, in PowerShell switch non si ferma alla prima corrispondenza: valuta tutte le alternative e ne esegue ogni ramo che corrisponde. Per fermarsi serve break. Nelle alternative possiamo anche usare un blocco di codice tra graffe come condizione: al suo interno $_ è il valore in esame.

Figura 11: senza break scattano tutti i rami corrispondenti

Opzioni di switch

Opzione Descrizione
-Exact Confronto di uguaglianza esatta (è il comportamento di default).
-Wildcard Le alternative sono caratteri jolly, come per -like.
-Regex Le alternative sono espressioni regolari, come per -match.
-CaseSensitive Distingue tra maiuscole e minuscole (di default non le distingue).
-File Invece di un valore legge le righe di un file di testo e le valuta una alla volta.

Combiniamo switch -Wildcard con foreach per classificare i file della cartella di test:

Figura 12: switch -Wildcard applicato ai file

Condizioni e pipeline: Where-Object

Gli operatori di confronto sono anche il cuore di Where-Object, il cmdlet che filtra gli oggetti in arrivo dalla pipeline. Per ogni oggetto la condizione tra graffe viene valutata e solo quelli per cui è vera passano oltre. Possiamo scriverla in forma estesa, con $_ che rappresenta l’oggetto corrente, oppure in forma semplificata (da PowerShell 3.0) quando la condizione è un singolo confronto.

Figura 13: Where-Object con operatori di confronto e logici

Nel primo esempio abbiamo combinato due confronti con -and; nel secondo abbiamo usato la sintassi semplificata; nel terzo abbiamo confrontato la data di modifica con $limite, cioè “30 giorni fa” (le date si confrontano con gli stessi operatori dei numeri). Questo è esattamente il meccanismo che avevamo usato per cancellare i file più vecchi di 30 giorni.

Scorciatoie di PowerShell 7: ternario e ??

Dalla versione 7 PowerShell offre due scorciatoie per le decisioni più semplici. L’operatore ternario (tipo if the else in excell) condizione ? valoreSeVero : valoreSeFalso sostituisce un if/else su una riga sola, mentre l’operatore ?? (null-coalescing) restituisce il valore a sinistra e, se questo è $null, quello a destra. Attenzione: su PowerShell 5.1 non funzionano, quindi occhio!

Figura 14: operatore ternario e ??

Esempio pratico completo: classificare i file per età

Mettiamo insieme quanto visto: per ogni file calcoliamo da quanti giorni non viene modificato e, con una catena di if/elseif, lo classifichiamo. I file vuoti sono segnalati per primi, poi si guarda l’età. Il formato -f allinea le colonne.

Figura 15: classificazione dei file per dimensione ed età

Provate ora a sostituire l’ultima riga con Remove-Item sui file “da archiviare” o con Move-Item verso una cartella di archivio: con -WhatIf prima, mi raccomando!

Consigli Utili per Principianti

  1. Ricordatevi che = assegna e -eq confronta: è l’errore più frequente e PowerShell non lo segnala.
  2. Usate sempre le parentesi con -and e -or: rendono chiaro l’ordine di valutazione e il codice più leggibile.
  3. Attenzione agli array a sinistra: -eq e gli altri operatori di confronto diventano filtri; per sapere se un elemento è presente usate -contains o -in.
  4. Occhio a maiuscole e minuscole: di default non contano; usate -ceq, -clike, -cmatch quando servono.
  5. Ordinate bene gli elseif: vince la prima condizione vera; quindi, mettete per prime le più specifiche.
  6. Ricordate break nello switch: senza, tutte le alternative che corrispondono vengono eseguite.

Riepilogo Operatori e Costrutti

Operazione Operatore o costrutto Esempio
Uguale / diverso -eq -ne $a -eq 5
Maggiore / minore -gt -ge -lt -le $a -ge 10
Jolly -like -notlike $n -like “*.txt”
Espressione regolare -match -notmatch $n -match “^\d+”
Appartenenza -contains -in “a” -in $lista
Maiuscole significative -ceq -clike -cmatch $a -ceq “Ok”
Logica -and -or -not -xor ($a -gt 1) -and ($b -lt 9)
Una scelta if / elseif / else if ($a -gt 1) { … }
Molte scelte switch switch ($a) { 1 { … } }
Filtrare la pipeline Where-Object … | Where-Object Length -gt 1KB
Ternario (PS 7) ? : $a -gt 1 ? “sì” : “no”
Valore di default (PS 7) ?? $a ?? “n/d”

Conclusione

Con gli operatori di confronto, quelli logici e i costrutti if e switch i nostri script smettono di essere semplici elenchi di comandi e iniziano a ragionare. Il prossimo passo naturale è fare in modo che ripetano le operazioni da soli: ci vediamo alla prossima puntata per parlare di cicli.

Ricordate: fate pratica! Sperimentate gli esempi sulla cartella di test e provate a inventarne di nuovi.