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:
-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.