Jakiś czas temu przybliżyłem pojęcie potoku w PowerShell, aby świadomie i sprawnie wykorzystywać funkcjonalność przekazywania wartości pomiędzy poleceniami.

Tym razem chciałbym pójść krok dalej i pokazać, które elementy musisz zastosować we własnych funkcjach, aby również wspierały pobieranie wartości z potoku.

Akceptowanie danych z potoku

Dodaj atrybut ValueFromPipeline lub ValueFromPipelineByPropertyName do parametru, który ma akceptować dane wejściowe z potoku.

  • wybierz ValueFromPipelineByPropertyName (metoda ByPropertyName), jeśli chcesz przekazywać konkretną właściwość obiektu. Funkcja możesz zawierać kilka parametrów właśnie z takim atrybutem.
function Get-SystemVersion {
    [PSCustomObject]@{
        Version = 41
        System = 'SystemX'
    }
}
 
function Update-SystemVersion {
    param(
        [Parameter(ValueFromPipelineByPropertyName)]
        $Version,
        [Parameter(ValueFromPipelineByPropertyName)]
        $System
    )
    $Version + 1
    $System
}
Get-SystemVersion | Update-SystemVersion

Zobacz na przykładzie, właściwości obiektu z funkcji Get-SystemVersion mają takie same nazwy jak parametry funkcji Update-SystemVersion. To pozwoliło na przekazanie wartości poprzez potok.

Pamiętaj, aby przekazanie zadziałało, wymagana jest zgodność nazw właściwości i parametrów.

ValueFromPipelineByPropertyName PowerShell Potok Funkcja
  • wybierz ValueFromPipeline (metoda ByValue) , jeśli wolisz przekazać za pomocą jednego parametru cały obiekt. W natywnych cmdletach często można zauważyć wykorzystywane w tym celu parametr -InputObject.
function Get-SystemVersion {
    [PSCustomObject]@{
        Version = 41
        System = 'SystemX'
    }
}
 
function Update-SystemVersion {
    param(
        [Parameter(ValueFromPipeline)]
        $InputObject
    )
    $InputObject.Version + 1
    $InputObject.System
}
Get-SystemVersion | Update-SystemVersion

Zmiana atrybut na ValueFromPipeline, wymusiło zmodyfikowanie funkcji Update-SystemVersion . Teraz pracujemy z całym obiektem, zamiast z wartościami w zmiennych (i mamy w ten sposób dostęp do nadmiarowych danych).

ValueFromPipeline PowerShell Potok Funkcja

Po przykładach mogłoby się wydawać, że to wszystko, co potrzebujemy zrobić. Funkcje działają, dane są przekazyane. Jednak nie do końca…

Blok Process

Jeśli któryś z parametrów funkcji jest ustawiony na akceptowanie danych wejściowych potoku, a blok Process nie jest zdefiniowany, przetwarzanie rekord po rekordzie zakończy się niepowodzeniem.

Process PowerShell Potok Funkcja

W takim przypadku funkcja wykona się tylko raz, niezależnie od ilości danych na wyjściu poprzedniej funkcji.

Dlatego konieczne jest dodanie bloku Process, która spowoduję poprawnie przetwarzanie danych przekazywanych w potoku.

Process PowerShell Potok Funkcja
function Get-SystemVersion
{
    [PSCustomObject]@{
        Version = 41
        System  = 'SystemX'
    }
 
    [PSCustomObject]@{
        Version = 31
        System  = 'SystemY'
    }
}
 
function Update-SystemVersion
{
    param(
        [Parameter(ValueFromPipeline)]
        $InputObject
    )
    process
    {
        $InputObject.Version + 1
        $InputObject.System
    }
}
Get-SystemVersion | Update-SystemVersion

Z Process związane są jeszcze bloki End oraz Begin, które nie są wymagane, lecz niekiedy mogą okazać się przydatne. Będą to miejsca, gdzie wykonamy coś raz na początku i na końcu przetwarzania potoku.

Po więcej informacji odsyłam do dokumentacji.

Podsumowanie

Wystarczy tylko tyle, aby własne funkcje potrafiły przekazywać dane poprzez potok. Należy pamiętać o dwóch sprawach, odpowiednim atrybucie dla parametru/parametrów oraz bloku Process, który jest niezbędny do przetwarzania każdego rekordu.

Nie zapomnij również o odpowiedniej walidacji parametrów i sprawdzanie „przychodzących” wartości/obiektów do funkcji. Zwracam na to uwagę, mimo że to sprawa, o którą należy dbać niezależnie od tego, czy wykorzystujemy przekazywanie potokiem, czy nie.

22 Najważniejsze Wskazówki Pisania Skryptów PowerShell

Mateusz Nadobnik

Zachwycony językiem skryptowym Windows PowerShell. Swoją wiedzę, doświadczenia i spostrzeżenia opisuję na blogu.

read more