FOREACH loop


I föregående avsnitt gick vi igenom FOR-loopen, som är användbar när du vet hur många gånger du vill upprepa en kodsekvens – till exempel när du arbetar med räknare, index eller intervall av tal. Vi har också lärt oss att en FOR-loop kräver alltid tre delar: startvärde, villkor och steg, vilket gör den flexibel men ibland lite mer formell i sin syntax.

Däremot finns det situationer där du inte är intresserad av index eller iterationens ordning, utan bara vill gå igenom varje objekt i en samling (till exempel en lista med namn, filer, tjänster eller IP-adresser). För sådana uppgifter är FOREACH-loopen betydligt enklare, tydligare och mer naturlig att använda.

I detta avsnitt fokuserar vi därför på FOREACH – hur den fungerar, när den bör användas, och hur du kan använda den för att bearbeta olika typer av data i PowerShell.

Två sätt att iterera objekt i PowerShell

I PowerShell finns två närbesläktade sätt att loopa över en samling:

1) Foreach-sats (nyckelordet) – språkkonstruktion

foreach ($item in $collection) { ... }
  • Förklaring:
    • foreach är en språkkonstruktion – alltså en del av själva PowerShell-syntaxen, inte en cmdlet.
    • Den läser hela samlingen ($collection) in i minnet innan loopen startar. Det betyder att PowerShell först hämtar alla objekt, till exempel en lista eller array, och sedan arbetar på dem i minnet.
    • Därefter går PowerShell igenom ett objekt i taget ur samlingen (hämtas från minnet och läggs till variabeln $item).
    • Vid varje varv i loopen tilldelas variabeln $item det aktuella objektet.
    • Det gör foreach snabb och effektiv när du redan har en färdig samling i en variabel — till exempel efter att du har kört ett kommando och sparat resultatet.

2) ForEach-Object (cmdlet i pipen) – cmdlet

$collection | ForEach-Object { ... }   # alias: % 
  • Förklaring
    • ForEach-Object är en cmdlet – alltså ett PowerShell-kommando som körs i pipeline-flödet.
    • Den bearbetar objekt ett i taget medan de passerar genom pipelinen. Inget behöver läsas in i minnet på förhand.
    • Det gör att den är bättre vid stora datamängder eller när du kedjar flera cmdlets.
    • Varje objekt som kommer från föregående kommando blir tillgängligt som $_ , den automatiska variabeln som representerar det aktuella objektet i pipen.

Dessa två sätt gör samma sak logiskt (”för varje objekt, gör X”), men kontexten (variabel vs. pipeline) avgör vilket som känns mest naturligt.

Syntax (Foreach-sats)

foreach ($item in $collection) {
    # åtgärder för varje $item
}
  1. $item är loop-variabeln (ny referens för varje objekt i samlingen).
  2. $collection är samlingen (array, lista, resultatet från ett kommando m.m.).

Exempel på användning av FOREACH

  1. Hälsa på varje namn i en array
  2. Skriva ut talen 1 till 10
  3. Lista filer och mappar som finns i C:\
  4. Multiplikationstabeller 1–5 (varje 1–10)
  5. Visa de fem första tjänsterna (services)
  6. Är talen 1–25 delbara med 10?
  7. Multiplicera negativa tal (−5 till −1) med 2

1) Hälsa på varje namn i en array

$names = @("Alice", "Bob", "Charlie")
foreach ($name in $names) {
    Write-Host "Hello, $name!"
}
  • Utdata
    • Hello, Alice!
    • Hello, Bob!
    • Hello, Charlie!
  • Förklaring
    • @("Alice", "Bob", "Charlie") skapar en array med tre strängar.
    • $name tar värdet av varje element i tur och ordning.
    • Write-Host skriver direkt till konsolen. (Tips: Write-Host är bäst för ren skärmtext.)

Alternativ (pipeline)

$names = @("Alice", "Bob", "Charlie")
$names | ForEach-Object { "Hello, $_!" }
  • @("Alice", "Bob", "Charlie") skapar en array med tre strängar.
  • | skickar arrayen som pipeline-input till cmdleten ForEach-Object.
  • Inuti blocket { "Hello, $_!"} används den automatiska variabeln $_ , som representerar det aktuella objektet i pipen, i detta fall varje namn.

2) Skriva ut talen 1 till 10

$myArray = 1,2,3,4,5,6,7,8,9,10
foreach ($number in $myArray) {
    echo $number
}
  • Förklaring
    • echo är alias för Write-Output.
    • $myArray = 1,2,3,4,5,6,7,8,9,10 skapar en array (en lista) som innehåller heltalen 1 till 10.
    • foreach ($number in $myArray) börjar själva loopen.
      Den säger i princip: “För varje element i samlingen $myArray, tilldela värdet till den tillfälliga variabeln $number.” 
    • Det betyder att PowerShell:
      • Tar första värdet i arrayen (1), tilldelar det till $number, och kör kodblocket { echo $number }
      • Går vidare till nästa värde (2), tilldelar det till $number, och kör kodblocket igen
      • Och så vidare, tills alla värden i $myArray har bearbetats.
    • Vid varje iteration innehåller $number ett nytt värde från arrayen.

Enklare variant med range-operatorn ..:

foreach ($number in 1..10) {
    Write-Output $number
}
  • Förklaring
    • 1..10 genererar en sekvens av heltal från 1 till 10.
    • Varje iteration skickar talet till utdata (kan också pipas vidare).

3) Lista filer och mappar som finns i C:\

foreach ($entry in (Get-ChildItem -Path C:\)) {
    Write-Output $entry
}
  • Förklaring
    • Get-ChildItem -Path C:\
      • Hämtar alla objekt (filer och mappar) i katalogen C:\.
      • Varje objekt som returneras är ett .NET-objekt av typen System.IO.FileInfo (för filer) eller System.IO.DirectoryInfo (för mappar).
      • Resultatet är alltså en samling objekt, inte bara text.
    • foreach ($entry in (...))
      • Loopen tar ett objekt i taget ur resultatet från Get-ChildItem.
      • Vid varje varv tilldelas det aktuella objektet till variabeln $entry. Exempelvis:
        • Första iterationen tilldelas $entry = C:\Program Files
        • Nästa tilldelas $entry = C:\Windows
        • Sedan tilldelas $entry = C:\pagefile.sys
        • och så vidare.
    • Write-Output $entry
      • Skriver ut värdet av $entry till pipeline eller till skärmen, i exemplet till skärmen.
      • Eftersom $entry är ett objekt visas dess namn i standardformat.
      • (Skillnaden mot Write-Host är att Write-Output kan skickas vidare till andra kommandon i en pipeline, medan Write-Host bara visar text.)

eller så här:

Get-ChildItem -Path C:\ | ForEach-Object { $_ }
  • Förklaring
    • Get-ChildItem -Path C:\ hämtar alla objekt i katalogen C:\.
    • Dessa objekt är .NET-objekt av typerna:
      • System.IO.FileInfo (för filer)
      • System.IO.DirectoryInfo (för mappar)
    • | (pipeline) skickar varje objekt som hittas till nästa kommando i kedjan, ett i taget.
    • ForEach-Object { $_ } kör kodblocket { $_ } en gång för varje objekt som kommer genom pipen.
    • Den automatiska variabeln $_ representerar det aktuella objektet. I det här fallet visar den helt enkelt objektet som det är, vilket gör att PowerShell skriver ut fil- och mappnamn.

Filtrera gärna:

Get-ChildItem -Path C:\ -Directory | ForEach-Object { $_.FullName }
  • Visar bara mapparnas fulla sökvägar.

4) Multiplikationstabeller 1–5 (varje 1–10)

foreach ($i in 1..5) {
    foreach ($j in 1..10) {
        $result = $j * $i
        # Snyggt jämn kolumnlayout med -f -formatsträng:
        "{0,2} x {1,2} = {2,3}" -f $j, $i, $result
    }
    ""  # tom rad mellan tabellerna
}

Detta exempel visar hur nästade foreach-loopar fungerar — det vill säga en loop inuti en annan loop.

  • Den yttre loopen (foreach ($i in 1..5)) bestämmer vilken tabell som ska skrivas ut (tabell 1, tabell 2, … tabell 5).
  • Den inre loopen (foreach ($j in 1..10)) räknar från 1 till 10 och multiplicerar varje tal med värdet i den yttre loopen. På så sätt får du 10 rader för varje tabell.
  • Uttrycket "{0,2} x {1,2} = {2,3}" -f $j, $i, $result använder format-operatorn -f för att skapa en snyggt formaterad utskrift där talen högerjusteras i kolumner.
  • {0,2} betyder: skriv första värdet ($j) med bredden 2 tecken.
  • {1,2} betyder: skriv andra värdet ($i) med bredden 2.
  • {2,3} betyder: skriv tredje värdet ($result) med bredden 3.
  • Detta gör tabellen lättare att läsa, särskilt när talen blir tvåsiffriga.
  • Raden med en tom sträng ("") används för att lägga in en mellanrad mellan varje tabell, så att resultatet blir tydligt uppdelat.
  • Sammanfattning
    • Yttre loop (foreach ($i in 1..5)) väljer tabell (1–5)
    • Inre loop (foreach ($j in 1..10)) räknar 1–10 och beräknar produkterna
    • -f gör utskriften prydlig och justerad
    • Tom rad skapar luft mellan tabellerna
    • Resultatet blir fem separata, lättlästa multiplikationstabeller.

Tips: Om du vill ha rubriker per tabell:

foreach ($i in 1..5) {
    "Tabell $i"
    1..10 | ForEach-Object { "{0,2} x {1,2} = {2,3}" -f $_, $i, ($_ * $i) }
    ""
}

5) Visa de fem första tjänsterna (services)

foreach ($service in (Get-Service | Select-Object -First 5)) {
    Write-Host "Service name: $($service.Name)  Status: $($service.Status)"
}
  • Get-Service | Select-Object -First 5
    • Get-Service hämtar en lista över alla tjänster (services) på datorn.
    • Varje tjänst representeras som ett objekt med flera egenskaper, t.ex. Name, DisplayName, Status, ServiceType, osv.
  • Select-Object -First 5 begränsar resultatet till de första fem tjänsterna.
  • foreach ($service in (...))
    • foreach är en språkkonstruktion (loop) som går igenom varje objekt i samlingen, ett i taget.
    • Variabeln $service får i varje varv ett av service-objekten som hämtats i parentesen.
  • Write-Host "Service name: $($service.Name) Status: $($service.Status)"
    • Write-Host skriver text direkt till skärmen.
    • Inuti textsträngen används uttrycks-interpolering ($()):
  • $($service.Name) hämtar namnet på tjänsten.
  • $($service.Status) hämtar statusen (t.ex. Running, Stopped).
  • $() används för att PowerShell ska utvärdera uttrycket inuti parentesen innan texten skrivs ut.

Exempel på utdata (varierar per dator)

Service name: AdobeARMservice  Status: Running
Service name: AppIDSvc         Status: Stopped
...

Vid filtrering

Get-Service | Where-Object Status -eq 'Running' | Select-Object -First 5 |
ForEach-Object { "Running: $($_.Name)" }
  • Get-Service hämtar alla tjänster (services) på systemet.
    Varje tjänst är ett objekt med flera egenskaper, bland annat Name, DisplayName, Status.
  • Where-Object Status -eq 'Running' filtrerar tjänsterna
    • Where-Object används för att välja ut de objekt som uppfyller ett villkor.
    • Status -eq 'Running' betyder “ta bara de tjänster där egenskapen Status är lika med Running”.
  • Select-Object -First 5 väljer de fem första objekten som finns kvar efter filtreringen.
  • ForEach-Object { "Running: $($_.Name)" }
    • Här används cmdleten ForEach-Object för att bearbeta varje objekt som kommer genom pipen.
    • Varje tjänst representeras i loopen som $_ (den automatiska variabeln för “aktuellt objekt”).
    • Inuti blocket { ... } skapas en textsträng:
  • "Running: $($_.Name)" där $($_.Name) hämtar namnet på den aktuella tjänsten.
  • PowerShell skriver ut varje textsträng i tur och ordning.

6) Är talen 1–25 delbara med 10?

foreach ($n in 1..25) {
    if ($n % 10 -eq 0) {
        "$n is like totally divisible by ten"
    }
}
  • Uttrycket 1..25 skapar en sekvens av heltal från 1 till 25.
    • Det är alltså samma som att skriva: @(1, 2, 3, 4, ..., 25)
    • Denna lista används som samlingen som loopen ska iterera över.
  • foreach ($n in 1..25) startar foreach-loopen.
    • Variabeln $n kommer att få ett nytt värde vid varje iteration, från 1 till 25.
    • Alltså: första varvet $n = 1, andra varvet $n = 2, … och sista $n = 25.
  • if ($n % 10 -eq 0) villkoret kontrollerar om $n är jämnt delbart med 10.
    • Operatorn % betyder modulo – den returnerar resten vid division.
      • Exempel:
      • 10 % 10 = 0 (inga rester, alltså delbart)
      • 15 % 10 = 5 (resten 5, alltså inte delbart)
    • Så uttrycket $n % 10 -eq 0 betyder “Om talet $n går jämnt upp i 10, gör detta...”
    • "$n is like totally divisible by ten"
  • Om villkoret i if-satsen är sant, skriver PowerShell ut texten.
  • Eftersom strängen står ensam i blocket, returneras och visas den automatiskt i konsolen.
  • Utdata
10 is like totally divisible by ten
20 is like totally divisible by ten

7) Multiplicera negativa tal (−5 till −1) med 2

$negativeNumbers = -5..-1
foreach ($n in $negativeNumbers) { $n * 2 }
  • Förklaring
    • $negativeNumbers = -5..-1 skapar en sekvens av heltal från –5 till –1 och tilldelas dessa värde till $negativeNumbers.
    • PowerShells intervall-operator .. fungerar även med negativa tal.
    • Alltså: $negativeNumbers = @(-5, -4, -3, -2, -1)
  • foreach ($n in $negativeNumbers)
    • foreach-loopen går igenom varje element i listan, ett i taget:
      • Första varvet: $n = -5
      • Andra varvet: $n = -4
      • … och så vidare tills $n = -1.
  • $n * 2 multiplicerar det aktuella talet med 2.
  • Eftersom raden inte innehåller Write-Host eller Write-Output, returneras resultatet automatiskt i konsolen.
  • Beräkningarna blir:
    • -5 * 2 = -10
    • -4 * 2 = -8
    • -3 * 2 = -6
    • -2 * 2 = -4
    • -1 * 2 = -2
  • Resultat i konsolen
-10
-8
-6
-4
-2

Vanliga tips och fallgropar

  • Välj rätt form
    • Har du redan en samling i en variabel → foreach ($x in $collection) { ... }.
    • Bygger du ett pipeline-flöde → ... | ForEach-Object { ... }.
  • Prestanda och minne
    • ForEach-Object strömmar objekt (bra för stora mängder).
    • Foreach-satsen materialiserar samlingen först (snabb i ren loop, men kräver att allt får plats).
  • Skriv ut rätt
    • Write-Output för data som kanske ska vidare i pipeline.
    • Write-Host för ren skärmtext (färg, rubriker).
  • Undvik att mutera samlingen du itererar
    • Lägg hellre till/ta bort objekt i en separat lista under loopen.
  • Formattering
    • Använd -f för kolumnsnyggt resultat när sifferkolumner ska läsas av människor.
  • $_ vs. namngiven variabel
  • I pipeline använder du oftast $_ . I foreach-satsen är en namngiven loopvariabel (t.ex. $item) oftast tydligare i undervisningsmaterial.

4) Multiplikationstabeller 1–5 (varje 1–10)

foreach ($i in 1..5) {
    foreach ($j in 1..10) {
        $result = $j * $i
        # Snyggt jämn kolumnlayout med -f -formatsträng:
        "{0,2} x {1,2} = {2,3}" -f $j, $i, $result
    }
    ""  # tom rad mellan tabellerna
}

Detta exempel visar hur nästade foreach-loopar fungerar — det vill säga en loop inuti en annan loop.

  • Den yttre loopen (foreach ($i in 1..5)) bestämmer vilken tabell som ska skrivas ut (tabell 1, tabell 2, … tabell 5).
  • Den inre loopen (foreach ($j in 1..10)) räknar från 1 till 10 och multiplicerar varje tal med värdet i den yttre loopen. På så sätt får du 10 rader för varje tabell.
  • Uttrycket "{0,2} x {1,2} = {2,3}" -f $j, $i, $result använder format-operatorn -f för att skapa en snyggt formaterad utskrift där talen högerjusteras i kolumner.
  • {0,2} betyder: skriv första värdet ($j) med bredden 2 tecken.
  • {1,2} betyder: skriv andra värdet ($i) med bredden 2.
  • {2,3} betyder: skriv tredje värdet ($result) med bredden 3.
  • Detta gör tabellen lättare att läsa, särskilt när talen blir tvåsiffriga.
  • Raden med en tom sträng ("") används för att lägga in en mellanrad mellan varje tabell, så att resultatet blir tydligt uppdelat.
  • Sammanfattning
    • Yttre loop (foreach ($i in 1..5)) väljer tabell (1–5)
    • Inre loop (foreach ($j in 1..10)) räknar 1–10 och beräknar produkterna
    • -f gör utskriften prydlig och justerad
    • Tom rad skapar luft mellan tabellerna
    • Resultatet blir fem separata, lättlästa multiplikationstabeller.

Tips: Om du vill ha rubriker per tabell:

foreach ($i in 1..5) {
    "Tabell $i"
    1..10 | ForEach-Object { "{0,2} x {1,2} = {2,3}" -f $_, $i, ($_ * $i) }
    ""
}

5) Visa de fem första tjänsterna (services)

foreach ($service in (Get-Service | Select-Object -First 5)) {
    Write-Host "Service name: $($service.Name)  Status: $($service.Status)"
}
  • Get-Service | Select-Object -First 5
    • Get-Service hämtar en lista över alla tjänster (services) på datorn.
    • Varje tjänst representeras som ett objekt med flera egenskaper, t.ex. Name, DisplayName, Status, ServiceType, osv.
  • Select-Object -First 5 begränsar resultatet till de första fem tjänsterna.
  • foreach ($service in (...))
    • foreach är en språkkonstruktion (loop) som går igenom varje objekt i samlingen, ett i taget.
    • Variabeln $service får i varje varv ett av service-objekten som hämtats i parentesen.
  • Write-Host "Service name: $($service.Name) Status: $($service.Status)"
    • Write-Host skriver text direkt till skärmen.
    • Inuti textsträngen används uttrycks-interpolering ($()):
  • $($service.Name) hämtar namnet på tjänsten.
  • $($service.Status) hämtar statusen (t.ex. Running, Stopped).
  • $() används för att PowerShell ska utvärdera uttrycket inuti parentesen innan texten skrivs ut.

Exempel på utdata (varierar per dator)

Service name: AdobeARMservice  Status: Running
Service name: AppIDSvc         Status: Stopped
...

Vid filtrering

Get-Service | Where-Object Status -eq 'Running' | Select-Object -First 5 |
ForEach-Object { "Running: $($_.Name)" }
  • Get-Service hämtar alla tjänster (services) på systemet.
    Varje tjänst är ett objekt med flera egenskaper, bland annat Name, DisplayName, Status.
  • Where-Object Status -eq 'Running' filtrerar tjänsterna
    • Where-Object används för att välja ut de objekt som uppfyller ett villkor.
    • Status -eq 'Running' betyder “ta bara de tjänster där egenskapen Status är lika med Running”.
  • Select-Object -First 5 väljer de fem första objekten som finns kvar efter filtreringen.
  • ForEach-Object { "Running: $($_.Name)" }
    • Här används cmdleten ForEach-Object för att bearbeta varje objekt som kommer genom pipen.
    • Varje tjänst representeras i loopen som $_ (den automatiska variabeln för “aktuellt objekt”).
    • Inuti blocket { ... } skapas en textsträng:
  • "Running: $($_.Name)" där $($_.Name) hämtar namnet på den aktuella tjänsten.
  • PowerShell skriver ut varje textsträng i tur och ordning.

6) Är talen 1–25 delbara med 10?

foreach ($n in 1..25) {
    if ($n % 10 -eq 0) {
        "$n is like totally divisible by ten"
    }
}
  • Uttrycket 1..25 skapar en sekvens av heltal från 1 till 25.
    • Det är alltså samma som att skriva: @(1, 2, 3, 4, ..., 25)
    • Denna lista används som samlingen som loopen ska iterera över.
  • foreach ($n in 1..25) startar foreach-loopen.
    • Variabeln $n kommer att få ett nytt värde vid varje iteration, från 1 till 25.
    • Alltså: första varvet $n = 1, andra varvet $n = 2, … och sista $n = 25.
  • if ($n % 10 -eq 0) villkoret kontrollerar om $n är jämnt delbart med 10.
    • Operatorn % betyder modulo – den returnerar resten vid division.
      • Exempel:
      • 10 % 10 = 0 (inga rester, alltså delbart)
      • 15 % 10 = 5 (resten 5, alltså inte delbart)
    • Så uttrycket $n % 10 -eq 0 betyder “Om talet $n går jämnt upp i 10, gör detta...”
    • "$n is like totally divisible by ten"
  • Om villkoret i if-satsen är sant, skriver PowerShell ut texten.
  • Eftersom strängen står ensam i blocket, returneras och visas den automatiskt i konsolen.
  • Utdata
10 is like totally divisible by ten
20 is like totally divisible by ten

7) Multiplicera negativa tal (−5 till −1) med 2

$negativeNumbers = -5..-1
foreach ($n in $negativeNumbers) { $n * 2 }
  • Förklaring
    • $negativeNumbers = -5..-1 skapar en sekvens av heltal från –5 till –1 och tilldelas dessa värde till $negativeNumbers.
    • PowerShells intervall-operator .. fungerar även med negativa tal.
    • Alltså: $negativeNumbers = @(-5, -4, -3, -2, -1)
  • foreach ($n in $negativeNumbers)
    • foreach-loopen går igenom varje element i listan, ett i taget:
      • Första varvet: $n = -5
      • Andra varvet: $n = -4
      • … och så vidare tills $n = -1.
  • $n * 2 multiplicerar det aktuella talet med 2.
  • Eftersom raden inte innehåller Write-Host eller Write-Output, returneras resultatet automatiskt i konsolen.
  • Beräkningarna blir:
    • -5 * 2 = -10
    • -4 * 2 = -8
    • -3 * 2 = -6
    • -2 * 2 = -4
    • -1 * 2 = -2
  • Resultat i konsolen
-10
-8
-6
-4
-2