Condividi tramite


Capitolo 6 - Controllo del flusso

Scrittura di script

Quando si passa dalla scrittura di PowerShell a riga singola alla scrittura di script, sembra più complicato di quanto sia. Uno script non è altro che gli stessi comandi o simili che esegui in modo interattivo nella console di PowerShell, tranne per il fatto che li salvi come file .ps1. Esistono alcuni costrutti di scripting che è possibile usare, ad esempio un ciclo foreach anziché il cmdlet ForEach-Object. Le differenze possono generare confusione per i principianti quando si considera che foreach è sia una parola chiave del linguaggio che un alias per il cmdlet ForEach-Object.

Ciclo

Uno degli aspetti migliori di PowerShell è la scalabilità. Dopo aver appreso come eseguire un'attività per un singolo elemento, l'applicazione della stessa azione a centinaia di elementi è quasi semplice. Scorrere gli elementi usando uno dei diversi tipi di cicli in PowerShell.

ForEach-Object

ForEach-Object è un cmdlet per l'iterazione degli elementi in una pipeline, ad esempio con un comando PowerShell a linea singola. ForEach-Object trasmette gli oggetti attraverso la pipeline.

Anche se il Module parametro di Get-Command accetta più valori stringa, li accetta solo tramite l'input della pipeline in base al nome della proprietà. Nello scenario seguente, se si desidera inviare tramite pipe due valori stringa a Get-Command da usare con il parametro del modulo , è necessario usare il cmdlet ForEach-Object.

'ActiveDirectory', 'SQLServer' |
    ForEach-Object {Get-Command -Module $_} |
    Group-Object -Property ModuleName -NoElement |
    Sort-Object -Property Count -Descending
Count Name
----- ----
  147 ActiveDirectory
   82 SqlServer

Nell'esempio precedente $_ è l'oggetto corrente. A partire da PowerShell versione 3.0, è possibile usare $PSItem anziché $_. La maggior parte degli utenti esperti di PowerShell preferisce usare $_ perché è compatibile con le versioni precedenti e meno da digitare.

Quando si usa la parola chiave foreach, è necessario archiviare gli elementi in memoria prima di scorrere tali elementi, il che potrebbe essere difficile se non si conosce quanti elementi ci sono.

$ComputerName = 'DC01', 'WEB01'
foreach ($Computer in $ComputerName) {
    Get-ADComputer -Identity $Computer
}
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName       : dc01.mikefrobbins.com
Enabled           : True
Name              : DC01
ObjectClass       : computer
ObjectGUID        : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName    : DC01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :

DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName       : web01.mikefrobbins.com
Enabled           : True
Name              : WEB01
ObjectClass       : computer
ObjectGUID        : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName    : WEB01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :

Molte volte è necessario un ciclo, ad esempio foreach o ForEach-Object. In caso contrario, viene visualizzato un messaggio di errore.

Get-ADComputer -Identity 'DC01', 'WEB01'
Get-ADComputer : Cannot convert 'System.Object[]' to the type
'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter
'Identity'. Specified method is not supported.
At line:1 char:26
+ Get-ADComputer -Identity 'DC01', 'WEB01'
+                          ~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-ADComputer], Parame
   terBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.ActiveDirecto
   ry.Management.Commands.GetADComputer

In altri casi, è possibile ottenere gli stessi risultati eliminando il ciclo. Consultare la guida del cmdlet per comprendere le opzioni.

'DC01', 'WEB01' | Get-ADComputer
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName       : dc01.mikefrobbins.com
Enabled           : True
Name              : DC01
ObjectClass       : computer
ObjectGUID        : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName    : DC01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :

DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName       : web01.mikefrobbins.com
Enabled           : True
Name              : WEB01
ObjectClass       : computer
ObjectGUID        : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName    : WEB01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :

Come si può notare negli esempi precedenti, il parametro identity per Get-ADComputer accetta solo un singolo valore quando viene fornito tramite l'input del parametro. Tuttavia, usando la pipeline, è possibile inviare più valori al comando perché i valori vengono elaborati uno alla volta.

Per

Un ciclo for esegue l'iterazione mentre una condizione specificata è vera. Non uso spesso il ciclo for, ma ha i suoi usi.

for ($i = 1; $i -lt 5; $i++) {
    Write-Output "Sleeping for $i seconds"
    Start-Sleep -Seconds $i
}
Sleeping for 1 seconds
Sleeping for 2 seconds
Sleeping for 3 seconds
Sleeping for 4 seconds

Nell'esempio precedente il ciclo esegue l'iterazione quattro volte iniziando con il numero uno e continuando fino a quando la variabile del contatore $i è minore di 5. Dorme per un totale di 10 secondi.

Fare

In PowerShell sono disponibili due cicli di do diversi: do until e do while. do until viene eseguito fino a quando la condizione specificata è falsa.

L'esempio seguente è un gioco di numeri che continua fino a che il valore che indovini è uguale al numero generato dal cmdlet Get-Random.

$number = Get-Random -Minimum 1 -Maximum 10
do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    } elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
until ($guess -eq $number)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3

Do While è l'opposto. Viene eseguito fino a quando la condizione specificata è valutata come vero.

$number = Get-Random -Minimum 1 -Maximum 10
do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    } elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
while ($guess -ne $number)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3
Too low!
What's your guess?: 4

Gli stessi risultati vengono ottenuti con un ciclo Do While invertendo la condizione di test a non uguale.

I cicli do vengono sempre eseguiti almeno una volta perché la condizione viene valutata alla fine del ciclo.

Mentre

Analogamente al ciclo do while, viene eseguito un ciclo while purché la condizione specificata sia vera. La differenza, tuttavia, è che un ciclo while valuta la condizione all'inizio del ciclo prima dell'esecuzione di qualsiasi codice. Pertanto, non viene eseguito se la condizione viene valutata come falsa.

Nell'esempio seguente viene calcolato il giorno in cui si trova il Giorno del Ringraziamento negli Stati Uniti. È sempre il quarto giovedì di novembre. Il ciclo inizia con il 22° giorno di novembre e aggiunge un giorno, mentre il giorno della settimana non è uguale a giovedì. Se il 22 è giovedì, il ciclo non viene eseguito affatto.

$date = Get-Date -Date 'November 22'
while ($date.DayOfWeek -ne 'Thursday') {
    $date = $date.AddDays(1)
}
Write-Output $date
Thursday, November 23, 2017 12:00:00 AM

interrompi, continua e restituisci

La parola chiave break è progettata per uscire da un ciclo e viene spesso usata con l'istruzione switch. Nell'esempio seguente, break fa sì che il ciclo venga terminato dopo la prima iterazione.

for ($i = 1; $i -lt 5; $i++) {
    Write-Output "Sleeping for $i seconds"
    Start-Sleep -Seconds $i
    break
}
Sleeping for 1 seconds

La parola chiave continue è progettata per passare all'iterazione successiva di un ciclo.

Nell'esempio seguente vengono restituiti i numeri 1, 2, 4 e 5. Ignora il numero 3 e continua con l'iterazione successiva del ciclo. Come break, continue interrompe il ciclo, ma solo durante l'iterazione corrente. L'esecuzione continua con l'iterazione successiva invece di interrompere il ciclo e fermarsi.

while ($i -lt 5) {
    $i += 1
    if ($i -eq 3) {
        continue
    }
    Write-Output $i
}
1
2
4
5

La parola chiave return è progettata per uscire dall'ambito esistente.

Si noti nell'esempio seguente che return restituisce il primo risultato e quindi esce dal ciclo.

$number = 1..10
foreach ($n in $number) {
    if ($n -ge 4) {
        return $n
    }
}
4

Una spiegazione più approfondita dell'istruzione di risultato è disponibile in uno degli articoli del mio blog: la parola chiave 'return' di PowerShell.

Sommario

In questo capitolo sono stati illustrati i diversi tipi di cicli esistenti in PowerShell.

Recensione

  1. Qual è la differenza tra il cmdlet ForEach-Object e l'istruzione foreach?
  2. Qual è il vantaggio principale dell'uso di un ciclo while anziché di un ciclo do while o di do until?
  3. In che modo le istruzioni break e continue differiscono?

Riferimenti