ForEach-Object

Wykonuje blok kodu dla każdego elementu w potoku.

ForEach-Object to cmdlet PowerShella, który bierze każdy obiekt płynący potokiem i wykonuje na nim blok kodu. To pętla w wersji potokowej: zamiast pisać klasyczne foreach ($x in $kolekcja), przepuszczasz dane przez | i obrabiasz je jeden po drugim. W praktyce sięgasz po niego, gdy chcesz coś zrobić z każdym plikiem, procesem czy wierszem, który zwrócił poprzedni cmdlet. Wewnątrz bloku bieżący element widzisz pod zmienną $_ (albo czytelniejszą $PSItem). Cmdlet ma dwa popularne aliasy: % oraz foreach — ten drugi mylnie wygląda jak słowo kluczowe pętli, ale w kontekście potoku to właśnie ten cmdlet.

Składnia i najważniejsze opcje

Podstawowa forma: | ForEach-Object { }

  • -Process — blok skryptu uruchamiany dla każdego elementu (to parametr domyślny, dlatego zwykle pomijasz jego nazwę).
  • -Begin — blok wykonywany raz, przed pierwszym elementem; dobry na inicjalizację liczników czy nagłówków.
  • -End — blok wykonywany raz, po ostatnim elemencie; idealny do podsumowań.
  • -MemberName — skrót, gdy chcesz tylko wywołać właściwość lub metodę elementu, np. | ForEach-Object Name.
  • -Parallel — uruchamia blok równolegle w osobnych wątkach (tylko PowerShell 7+); zmienne z zewnątrz wskazujesz przez $using:.
  • -ThrottleLimit — maksymalna liczba bloków działających jednocześnie przy -Parallel; domyślnie 5.
  • -InputObject — pozwala podać dane wprost, zamiast przez potok (rzadko używane ręcznie).

Przykłady użycia

  • 1..5 | ForEach-Object { $_ * 2 } — mnoży każdą liczbę z zakresu przez dwa i zwraca 2, 4, 6, 8, 10.
  • Get-ChildItem *.log | ForEach-Object { Rename-Item $_ ($_.BaseName + ".txt") } — zmienia rozszerzenie wszystkich plików .log na .txt.
  • Get-Process | ForEach-Object -Begin { $i = 0 } -Process { $i++ } -End { "Procesów: $i" } — zlicza procesy z użyciem bloków Begin/End.
  • Get-Service | ForEach-Object MachineName — zwraca samą właściwość MachineName każdej usługi dzięki -MemberName.
  • 1..10 | ForEach-Object -Parallel { Start-Sleep 1; "Gotowe $_" } -ThrottleLimit 4 — wykonuje zadania równolegle, maksymalnie cztery naraz (PowerShell 7+).

Częste błędy i pułapki

Najczęstsza wpadka to mylenie $_ z elementem zewnętrznej pętli — przy zagnieżdżonych ForEach-Object każdy poziom ma własne $_, więc czasem warto zapisać wartość do nazwanej zmiennej. -Parallel nie widzi twoich lokalnych zmiennych: musisz odwołać się przez $using:nazwa, inaczej dostaniesz $null i ciche błędy. Pamiętaj też, że -Parallel istnieje dopiero od PowerShella 7 — na Windows PowerShell 5.1 ten parametr nie zadziała. I jeszcze wydajność: dla milionów elementów klasyczne foreach ($x in ...) bywa wyraźnie szybsze niż ForEach-Object, bo nie płaci narzutu potoku za każdy obiekt. Równoległość ma sens głównie przy zadaniach I/O (sieć, dysk), a nie przy prostych obliczeniach.

Powiązane komendy: foreach (słowo kluczowe pętli), Where-Object, Select-Object, ForEach-Object -Parallel, Start-Job.