Magic Quadrant™ per la gestione degli accessi privilegiati 2025: Netwrix riconosciuta per il quarto anno consecutivo. Scarica il report.

Piattaforma
Centro risorseBlog
Spiegazione del ciclo Foreach in PowerShell: sintassi, esempi e migliori pratiche | Netwrix Blog | Insights per professionisti della cybersecurity e dell'IT

Spiegazione del ciclo Foreach in PowerShell: sintassi, esempi e migliori pratiche | Netwrix Blog | Insights per professionisti della cybersecurity e dell'IT

Feb 20, 2025

Il ciclo ForEach di PowerShell semplifica l'iterazione su collezioni come array, liste o output di pipeline, rendendolo essenziale per l'automazione e l'elaborazione dei dati. Esegue un blocco di codice per ogni elemento, supportando casi d'uso come rinominare file, aggiornare Active Directory utenti o analizzare log. Le migliori pratiche includono l'utilizzo di nomi di variabili chiari, la combinazione con la gestione degli errori e l'uso di ForEach-Object per compiti guidati dalla pipeline efficienti in termini di memoria.

Il ciclo foreach in PowerShell ti permette di iterare attraverso tutti gli elementi di una collezione ed eseguire un blocco di codice per ciascun elemento. Ad esempio, puoi utilizzare un ciclo foreach per creare un elenco di tutti i file in una directory per un'audizione, visualizzare tutti i processi in esecuzione sul sistema o spostare i vecchi file in un archivio.

Questo articolo dettaglia la sintassi del ciclo PowerShell foreach e ne esplora gli utilizzi comuni, completi di script di esempio. Poi spiega come evitare gli errori più comuni e offre le migliori pratiche per utilizzare i cicli foreach in modo efficace.

Iniziare con i cicli Foreach di PowerShell

Sintassi di base ed elaborazione

Ecco la sintassi di base del foreach statement:

      foreach ($item in $collection) {

    # Code to execute for each item

}

      

L'elaborazione di questo ciclo foreach procede come segue:

  1. PowerShell carica la collezione $collection in memoria e determina il numero di oggetti che contiene.
  2. Il primo oggetto da $collection viene assegnato alla variabile $item e il blocco di codice viene eseguito per quell'oggetto.
  3. Il valore di $item viene aggiornato al prossimo oggetto in $collection e il blocco di codice viene eseguito per quell'oggetto. Questo passaggio viene ripetuto fino a quando tutti gli oggetti in $collection sono stati elaborati.

Sintassi Avanzata

Il metodo foreach offre un modo più conciso per iterare sulle collezioni e può potenzialmente offrire prestazioni migliori. La sintassi è la seguente:

      $collection.ForEach({ <expression> })
      


Confronto tra la parola chiave Foreach, Foreach-Object e il metodo Foreach

La parola chiave Foreach, l'oggetto foreach-object e il metodo Foreach hanno uno scopo simile, ma presentano casi d'uso e comportamenti distinti.

ForEach Keyword

La parola chiave foreach viene utilizzata per iterare su una collezione di elementi, carica tutti gli elementi della collezione in memoria ed elabora tutti gli elementi contemporaneamente. Rendendola una scelta ideale quando si tratta di collezioni in memoria per un'elaborazione rapida.

ForEach-Object Cmdlet

Il cmdlet Foreach-object, d'altra parte, è un cmdlet orientato alla pipeline progettato per elaborare ciascun oggetto che scorre nella pipeline uno alla volta. Riduce il consumo di risorse come la memoria ed è adatto per scenari in cui caricare l'intera collezione in memoria non è pratico. Sebbene leggermente più lento del foreach a causa del sovraccarico della pipeline, è vantaggioso nell'utilizzo efficiente della memoria durante l'esecuzione dello script.

ForEach Method

Il metodo Foreach è stato introdotto in PowerShell 5; il metodo Foreach è utile su certi tipi di collezioni come array e liste, fornisce una sintassi concisa per eseguire azioni su ogni elemento. Il metodo Foreach è orientato agli oggetti e viene utilizzato quando vogliamo concatenare metodi e per collezioni in memoria è più efficiente del cmdlet foreach-object.

Nell'esempio seguente, otteniamo processi che consumano memoria superiore a 400 mb con foreach, foreach-object e metodo foreach.

      # Get all processes consuming more than 400MB of memory

$processes = Get-Process | Where-Object { $_.WorkingSet64 -gt 400MB }

# Using foreach keyword (Table Format)

Write-Host "`n=== Using foreach Keyword (Table Format) ===" -ForegroundColor Cyan

$output = foreach ($proc in $processes) {

    [PSCustomObject]@{

        "Process Name"  = $proc.ProcessName

        "PID"           = $proc.Id

        "Memory (MB)"   = [math]::Round($proc.WorkingSet64 / 1MB, 2)

    }

}

$output | Format-Table -AutoSize

# Using Foreach-Object (List Format)

Write-Host "`n=== Using Foreach-Object Cmdlet (List Format) ===" -ForegroundColor Green

$processes | ForEach-Object {

    Write-Output "Process Name : $($_.ProcessName)"

    Write-Output "PID          : $($_.Id)"

    Write-Output "Memory Usage : $([math]::Round($_.WorkingSet64 / 1MB, 2)) MB"

    Write-Output "-----------------------------------"

}

# Using .ForEach() Method (CSV-like Output)

Write-Host "`n=== Using .ForEach() Method (CSV-like Output) ===" -ForegroundColor Yellow

$processes.ForEach({

    "$($_.ProcessName),$($_.Id),$([math]::Round($_.WorkingSet64 / 1MB, 2)) MB"

}) | ForEach-Object { Write-Output $_ }
      
Image

Casi d'uso comuni

Visualizza tutti i numeri in un array

Lo script seguente eseguirà un ciclo attraverso un array di numeri e scriverà ciascuno nella console:

      # Define an array of numbers

$numbers = 1..5

# Loop through the array

foreach ($number in $numbers) {

    Write-Host "Number (foreach keyword): $number"

}

      
Image

Visualizza i nomi di tutti i file in una directory

L'esempio seguente di PowerShell foreach utilizza il cmdlet Get-ChildItem per recuperare i file da una directory specificata e visualizza il nome di ogni file:

      foreach ($file in Get-ChildItem -Path " D:\Office") {

    Write-Output $file.Name

}
      
Image

Manipolare ogni oggetto in una collezione

Lo script seguente ottiene tutti i processi il cui nome inizia per C o F, verifica se ciascun processo è in esecuzione e aggiunge la proprietà personalizzata isActive a ogni processo per documentarne lo stato:

      # Get all processes whose names start with 'C' or 'F'

$processes = Get-Process | Where-Object { $_.Name -like "C*" -or $_.Name -like "F*" }

foreach ($process in $processes) {

    $isActive = $process.Responding

    $process | Add-Member -NotePropertyName "IsActive" -NotePropertyValue $isActive

}

$processes | Format-Table -Property Name, Id, IsActive
      
Image

Tecniche avanzate

Elaborazione degli elementi in base ai propri criteri

Puoi usare If statements nei cicli foreach per eseguire azioni diverse in base alle caratteristiche di ogni oggetto in elaborazione. Lo script seguente ottiene tutti i file in una directory specificata ma restituisce i nomi di solo quelli più grandi di 10 kb:

      foreach ($file in Get-ChildItem -Path "D:\Office") {

  if ($file.Length -gt 10KB) {

    Write-Output $file.Name

  }

}
      
Image

Questo script potrebbe essere facilmente modificato per eseguire altre azioni sui file di grandi dimensioni in una directory anziché limitarsi a elencarli. Ad esempio, potresti copiarli in un'altra posizione, comprimerli o eliminarli in base a quando sono stati ultimamente accessi.

Utilizzando l'annidamento

Inserire un ciclo foreach all'interno di un altro è chiamato nidificazione. I cicli foreach nidificati possono essere utilizzati per iterare attraverso due o più collezioni ed eseguire operazioni che coinvolgono elementi di entrambe le collezioni. Ad esempio, la nidificazione può essere utilizzata per generare combinazioni di parametri per i test, creare prodotti cartesiani di insiemi o iterare su dati multidimensionali.

Lo script sottostante utilizza cicli foreach annidati per generare tutte le possibili combinazioni di elementi provenienti da due diversi array, uno con tre numeri e uno con tre lettere:

      $outerArray = 1..3

$innerArray = 'A', 'B', 'C'

foreach ($outer in $outerArray) {

  foreach ($inner in $innerArray) {

    Write-Output "$outer $inner"

  }

}
      
Image

Gestione degli errori

Se un ciclo foreach incontra un errore, lo script terminerà. Un esempio comune è quando il codice tenta di dividere per zero, il che non è matematicamente possibile. Il messaggio di errore risultante può aiutarti a identificare la causa dei problemi.

Puoi utilizzare un blocco Try-Catch per gestire potenziali problemi in modo elegante e assicurarti che lo script continui a elaborare altri elementi nella collezione. Nel seguente script, il blocco try tenta di risolvere un problema di divisione utilizzando ogni numero nella collezione. Se l'operazione ha successo, il risultato viene scritto sull'host; in caso contrario, il blocco catch visualizza un messaggio di errore in rosso. In entrambi i casi, il ciclo procede con l'elemento successivo nella collezione.

      # Sample collection of items.

$numbers = @(1, 2, 0, 4, 5)

foreach ($number in $numbers) {

  try {

    $result = 10 / $number

    Write-Host "10 divided by $number is: $result"

  } catch {

    Write-Host "Error: Cannot divide by zero. Skipping $number." -ForegroundColor Red

  }

}

      

Evitare gli errori comuni

Ecco alcuni errori che vengono spesso commessi con i cicli foreach e come evitarli.

Utilizzo dello stesso nome di variabile nei loop annidati

Utilizzare lo stesso nome di variabile in cicli nidificati può portare a comportamenti inaspettati e conflitti. Ad esempio, lo script seguente utilizza la stessa variabile $item sia nel ciclo esterno che in quello interno:\

      foreach ($item in $collection) {

  foreach ($item in $nestedCollection) { # Overwrites outer $item

    Write-Host $item

  }

}
      

Per evitare problemi, utilizza nomi di variabili univoci per ogni ciclo:

      foreach ($outerItem in $collection) {

  foreach ($innerItem in $nestedCollection) {

    Write-Host $innerItem

  }

}
      

Interrompere anticipatamente i cicli

Un'istruzione break può essere utilizzata per uscire da un ciclo foreach una volta che una condizione desiderata è soddisfatta. Tuttavia, l'uso improprio delle istruzioni break può terminare prematuramente il ciclo, portando a un'elaborazione incompleta della collezione.

Di conseguenza, usa break con attenzione. Considera alternative come continue per saltare iterazioni specifiche senza uscire dal ciclo:

Cicli infiniti

Se la condizione del ciclo non risulta mai falsa o la collezione viene modificata in modo improprio, il ciclo può continuare all'infinito. Ad esempio, mentre lo script seguente itera su una collezione, continua ad aggiungere nuovi elementi a quella collezione:

      $collection = @("Item1", "Item2", "Item3")

foreach ($item in $collection) {

  $collection.Add("NewItem")  # Changes collection size dynamically

}
      

Un modo per evitare questo ciclo infinito è fare una copia della collezione originale e poi iterare attraverso la copia, apportando modifiche all'originale:

      # Original collection

$collection = @("Item1", "Item2", "Item3")

# Iterate over a copy of the collection

foreach ($item in $collection.Clone()) {

  Write-Host "Processing $item"

  $collection.Add("NewItem")  # Modify the original collection safely

}

Write-Host "Final Collection: $collection"
      

Best Practices

Le seguenti migliori pratiche possono aiutarti ad utilizzare i cicli foreach più efficacemente.

Per i dati in pipeline, utilizzare il cmdlet foreach-object.

Come abbiamo visto, foreach in PowerShell carica una collezione in memoria e poi elabora ogni elemento in sequenza. Tuttavia, a volte è necessario elaborare oggetti passati attraverso una pipeline. In questi casi, utilizza il cmdlet foreach-object, che utilizza anche meno memoria. Per esempi, consulta questa guida Essential PowerShell Commands.

Massimizza la leggibilità e la manutenibilità degli script.

Per rendere i tuoi script più facili da leggere e mantenere, utilizza un'indentazione e spaziatura coerenti per i tuoi cicli foreach, aggiungi commenti significativi e mantieni il corpo del ciclo conciso definendo funzioni o metodi, come illustrato qui:

      # Define a collection of file paths

$filePaths = Get-ChildItem -Path "D:\Office" -File

# Process each file in the collection

foreach ($file in $filePaths) {

  # Check if the file is larger than 1KB

  if ($file.Length -gt 1KB) {

    # Log the file name and size

    Write-Host "Large file found: $($file.Name) - Size: $($file.Length / 1KB) KB"

  } else {

    # Skip smaller files

    Write-Host "Skipping small file: $($file.Name)"

  }

}
      
Image

Conclusione

Il ciclo foreach in PowerShell è uno strumento prezioso per automatizzare compiti che richiedono di iterare attraverso una collezione ed eseguire codice su ogni elemento, come la gestione di file e il controllo dei processi. Inizia sperimentando con gli esempi semplici forniti in questo articolo e poi passa a tecniche più avanzate come cicli annidati e gestione degli errori.

FAQ

Qual è la differenza tra un ciclo foreach e il cmdlet foreach-object?

Un ciclo foreach viene utilizzato per iterare su un array o un'altra collezione, che carica in memoria prima di elaborare i dati. Il cmdlet foreach-object viene utilizzato per elaborare oggetti passati attraverso una pipeline da un altro cmdlet.

Come gestisci gli errori in un ciclo foreach?

Utilizza un blocco try-catch per gestire le eccezioni con grazia.

È possibile uscire da un ciclo foreach in PowerShell?

Sì, puoi usare un'istruzione break per uscire da un ciclo foreach una volta che è stata soddisfatta una condizione desiderata. Qui, il ciclo viene interrotto quando il numero 5 viene raggiunto nella collezione, quindi solo i numeri da 1 a 4 vengono scritti sull'host:

      foreach ($number in 1..10) {

    if ($number -eq 5) { break }

    Write-Host $number

}

      
Image

Come si annidano i cicli foreach?

Per nidificare i cicli foreach, inserisci un ciclo all'interno di un altro. Per evitare errori, assicurati di utilizzare nomi di variabili univoci per i diversi cicli. Lo script seguente utilizza cicli foreach nidificati per iterare due collezioni e visualizzare tutte le possibili combinazioni degli elementi in tali collezioni:

      $outerCollection = @(1, 2)

$innerCollection = @(3, 4)

foreach ($outerItem in $outerCollection) {

    foreach ($innerItem in $innerCollection) {

        Write-Host "Outer: $outerItem, Inner: $innerItem"

    }

}
      
Image

Condividi su

Scopri di più

Informazioni sull'autore

Asset Not Found

Tyler Reese

Vicepresidente della Gestione Prodotti, CISSP

Con più di due decenni nel settore della sicurezza del software, Tyler Reese conosce intimamente le sfide di identità e sicurezza in rapida evoluzione che le aziende affrontano oggi. Attualmente, ricopre il ruolo di direttore del prodotto per il portfolio di Netwrix Identity and Access Management, dove le sue responsabilità includono la valutazione delle tendenze di mercato, la definizione della direzione per la linea di prodotti IAM e, in ultima analisi, la soddisfazione delle esigenze degli utenti finali. La sua esperienza professionale spazia dalla consulenza IAM per le aziende Fortune 500 al lavoro come architetto aziendale di una grande compagnia diretta al consumatore. Attualmente detiene la certificazione CISSP.