Articles

ForEach and Where magic methods

ForEach and Where to dwa często używane pojęcia, które są dostępne w PowerShell od wersji 1, która ukazała się w 2006 roku. ForEach jest dostępny zarówno jako instrukcja, jak i cmdlet (foreach-Object), co pozwala na iterację przez zbiór obiektów i wykonanie jednej akcji dla każdego obiektu w tym zbiorze. Where jest dostępny jako cmdlet (Where-Object), pozwalający odfiltrować elementy w kolekcji, które nie przechodzą przez jakiś warunek, warunek, który może być oceniany za pomocą właściwości obiektów w kolekcji lub samych obiektów należących do kolekcji. Zdolność ForEach do podejmowania działań na elementach w kolekcji i zdolność gdzie do filtrowania kolekcji są funkcjami, które są bardzo przydatne i są zawarte w takiej czy innej formie w logice wielu skryptów, poleceń i modułów PowerShell, niezależnie od tego, jaka wersja PowerShell jest używana. W rzeczywistości są one tak intensywnie używane, że były obszarem skupienia dla poprawy wydajności, funkcjonalności i składni w wersjach PowerShell 3.0 i 4.0.

wraz z wydaniem Windows PowerShell 4.0, dwie nowe „magiczne” metody zostały wprowadzone dla typów kolekcji, które zapewniają nową składnię dostępu do ForEach i gdzie możliwości w Windows PowerShell. Metody te są trafnie nazwane ForEach i Where. Nazywam te metody „magią”, ponieważ są one dość magiczne w tym, jak działają w PowerShell. Nie pojawiają się one w wyjściu Get-Member, nawet jeśli zastosujesz-Force I request-MemberType All. Jeśli zakasasz rękawy i zagłębisz się w refleksję, możesz je znaleźć; jednak wymaga to szerokiego wyszukiwania, ponieważ są to prywatne metody rozszerzania zaimplementowane na prywatnej klasie. Jednak nawet jeśli nie są one wykrywalne bez zaglądania pod kołdrę, są tam, gdy ich potrzebujesz, są szybsze niż ich starsze odpowiedniki i zawierają funkcjonalność, która nie była dostępna w ich starszych odpowiednikach, stąd „magiczne” uczucie, z którym zostawiają cię, gdy używasz ich w PowerShell. Niestety, metody te pozostają nieudokumentowane nawet dzisiaj, prawie rok od ich publicznego wydania, więc wiele osób nie zdaje sobie sprawy z mocy, która jest dostępna w tych metodach. W tym artykule postaramy się to poprawić, wyjaśniając, gdzie można ich używać i jak działają, abyś mógł wykorzystać tę magię podczas korzystania z PowerShell.

uwaga na temat PowerShell 3.0

zanim przejdę do wyjaśnienia, jak działa ForEach i gdzie działają metody, muszę wspomnieć coś w odniesieniu do tych dwóch metod i PowerShell 3.0. Chociaż prawdą jest, że metody ForEach i Where były dostępne tylko w PowerShell 4.0 i późniejszych wersjach, PowerShell 3.0 jest nadal bardzo szeroko stosowany w wielu środowiskach, a jeśli nie używasz PowerShell w środowisku, które ustandaryzowało PowerShell 4.0 i nowsze, możesz chcieć skorzystać ze składni dostarczonej przez nowe metody podczas korzystania z PowerShell 3.0. Czułem, że jest to ograniczenie warte rozwiązania, więc w ramach modułu TypePx, który niedawno opublikowałem na GitHub i w Galerii zasobów PowerShell (aka publiczne repozytorium PowerShellGet, obecnie w ograniczonym podglądzie), włączyłem metody skryptów ForEach i Where, które są funkcjonalnie równoważne metodom wprowadzonym w PowerShell 4.0, dzięki czemu można wykorzystać nową składnię i funkcjonalność, nawet jeśli używasz PowerShell 3.0. Istnieje kilka niedociągnięć w tej realizacji, które podkreślę w dalszej części tego artykułu.

metoda ForEach

ForEach jest metodą, która pozwala szybko iterować przez zbiór obiektów i podjąć pewne działania na każdym obiekcie w tym zbiorze. Metoda ta zapewnia szybszą wydajność niż jej starsze odpowiedniki (Instrukcja foreach i aplet poleceń foreach-Object), a także upraszcza niektóre z najczęstszych działań, które chcesz wykonać na obiektach w kolekcji. Wszystkie obiekty, które są wyprowadzane przez tę metodę, są zwracane w ogólnym zbiorze typu system.Kolekcje.ObjectModel.Kolekcja1.

istnieje sześć obsługiwanych sposobów wywołania tej metody, a każdy z nich zostanie szczegółowo wyjaśniony poniżej. Obsługiwane argumenty, które mogą być użyte podczas wywoływania metody ForEach są następujące:

  • ForEach(scriptblock expression)
  • ForEach(type convertToType)
  • ForEach(string propertyName)
  • ForEach(string propertyName, object newValue)
  • ForEach(string methodName)
  • ForEach(string methodName, object arguments)
  • ForEach(scriptblock expression, object arguments)

zauważ, że są to obsługiwane pary argumentów, a nie różne przeciążenia dostępne dla metody foreach. Używanie par argumentów innych niż te może skutkować błędami, które nie identyfikują jednoznacznie, na czym polega rzeczywisty problem.

ForEach(wyrażenie scriptblock) i ForEach(wyrażenie scriptblock, argumenty obiektu)

jeśli przekażesz wyrażenie bloku skryptowego do metody ForEach, będziesz w stanie wykonać te same zadania, co w bloku skryptowym, którego używasz z instrukcją foreach lub poleceniem cmdlet foreach-Object. Podobnie jak w przypadku apletów poleceń foreach-Object, zmienne $_ i $PSItem odwołują się do bieżącego elementu, który jest przetwarzany. Wszelkie argumenty, które podasz poza początkowym argumentem bloku skryptów, zostaną użyte jako argumenty dla bloku skryptów. Tak samo działa parametr-ArgumentList w cmdlecie ForEach-Object. Oto przykład pokazujący, w jaki sposób możesz użyć tego do wykonania bloku skryptu dla każdego elementu w kolekcji:

# Get a set of services$services = Get-Service c*# Display the names and display names of all services in the collection$services.foreach{"$($_.Name) ($($_.DisplayName))"}# Select a property name to expand using a script block argument$services.foreach({param($PropertyName); $_.$PropertyName}, 'DisplayName')

być może zauważyłeś coś dziwnego w tej składni, ponieważ nie zawiniłem samego bloku skryptu w nawiasy. Możesz owinąć go w nawiasy okrągłe, jednak jest to opcjonalne w PowerShell 4.0 lub nowszym, ponieważ parser PowerShell został ulepszony, aby umożliwić pomijanie nawiasów za każdym razem, gdy wywołujesz metodę, która akceptuje pojedynczy argument bloku skryptu. Podobnie jak polecenie foreach i polecenie poleceń foreach-Object, podany blok skryptów jest wywoływany w bieżącym zakresie. Oznacza to, że wszelkie przypisania zmiennych, które wykonasz wewnątrz tego bloku skryptów, będą utrzymywać się po zakończeniu wykonywania metody ForEach.

ForEach(type convertToType)

unikalny dla metody ForEach, możesz przekazać typ do metody ForEach, jeśli chcesz przekonwertować każdy element w kolekcji na inny typ. Na przykład wyobraź sobie, że posiadasz zbiór obiektów i chcesz je przekonwertować na ich ciągi znaków. Oto jak to by wyglądało w przypadku metody ForEach:

# Get a collection of processes$processes = Get-Process# Convert the objects in that collection into their string equivalent$processes.foreach()

można było wykonać to samo zadanie, wpisując kolekcję na tablicę typu string (np. ]$processes), a wpisanie tablicy jest w rzeczywistości znacznie szybsze, jednak istnieje bardzo duża szansa, że nie zauważyłbyś różnicy w czasie wykonania, chyba że pracowałeś z bardzo, bardzo dużą kolekcją. Pomimo różnicy czasu, w pewnych sytuacjach preferuję składnię metody ForEach, jeśli pozwala mi ona zachować elegancję w implementacji, unikając dodatkowych nawiasów okrągłych w pisanych przeze mnie skryptach.

ForEach(string propertyName)

w PowerShell 3.0 i nowszych, drugi zestaw parametrów został dodany do foreach-Object, aby umożliwić łatwiejsze odzyskanie wartości określonej właściwości, po prostu przekazując nazwę właściwości jako jedyną wartość parametru dla foreach-Object. Ta wygoda została zaoferowana również w metodzie ForEach. Oto przykład pokazujący, jak można iterować za pomocą Kolekcji i zwrócić właściwość tej kolekcji:

# Get all services whose name starts with "w"$services = Get-Service w*# Return the names of those services$services.foreach('Name')

oczywiście od wersji 3.0 PowerShella można po prostu wywołać $services.Name aby uzyskać nazwy wszystkich usług, a to zakończy się szybciej niż alternatywa metody ForEach (chociaż zauważysz różnicę wydajności tylko w bardzo dużych zbiorach w kolejności setek tysięcy obiektów); działa to jednak tylko dla właściwości, które nie znajdują się w samej kolekcji, i jest to składnia, z którą niektórzy skrypterzy nie są zadowoleni ze względu na ukryty charakter tego, co robi Komenda. Nowa składnia metody ForEach zapewnia bardziej wyraźną alternatywę, która ma dodatkową zaletę bycia trochę bardziej samodzielnym dokumentowaniem.

ForEach(string nazwa_właściwości, obiekt newValue)

nie tylko można pobrać właściwość dla kolekcji obiektów, można również ustawić właściwość dla kolekcji obiektów. Jest to funkcjonalność, która nie jest dostępna w innych foreach, chyba że wyraźnie utworzysz blok skryptów, aby to zrobić. Aby ustawić właściwość, wystarczy podać nazwę właściwości i wartość, której chcesz użyć podczas ustawiania tej właściwości, w następujący sposób:

# Note, this is not a realistic example# This would be used more commonly on configuration data$services = Get-Service c*# Now change the display names of every service to some new value$services.foreach('DisplayName','Hello')

podobnie jak przyporządkowania, które wykonasz za pomocą operatora equals, PowerShell spróbuje przekonwertować cokolwiek podasz jako nową wartość na odpowiedni typ dla przypisanej właściwości.

ForEach(string nazwa_metody) i ForEach(string nazwa_metody, argumenty obiektu)

aby wywołać metodę, wystarczy podać nazwę metody jako pierwszy argument, a następnie argumenty dla tej metody jako drugi, trzeci, czwarty, itd. argumenty. Jeśli metoda nie przyjmuje żadnych argumentów, możesz po prostu podać nazwę Metody i zostanie ona wywołana bez żadnych argumentów. Oto przykład pokazujący, jak można zabić kilka procesów uruchamiających określony program:

# Get all processes running Chrome$processes = Get-Process -Name Chrome# Now kill all of those processes$processes.foreach('Kill')

oto kolejny przykład, tym razem przy użyciu metody z argumentami, pokazując jednocześnie, w jaki sposób można zweryfikować, że polecenia są zgodne z najlepszymi praktykami, używając odpowiednich nazw i aliasów dla powszechnie używanych parametrów:

# Get all commands that have a ComputerName parameter$cmds = Get-Command -ParameterName ComputerName# Now show a table making sure the parameter names and aliases are consistent$cmds.foreach('ResolveParameter','ComputerName') | Format-Table Name,Aliases

jak widać z tych wyników, istnieją zdecydowanie pewne niespójności w implementacji parametrów nazwy komputera, które należy poprawić.

, która obejmuje wszystkie funkcje, które są obecnie dostępne w metodzie ForEach. Jak widać, nie ma zbyt wielu nowych funkcji oferowanych w tej metodzie, ale ulepszenia składni podczas wykonywania prostego zadania na kolekcji obiektów są miłe, a ulepszenia wydajności metody ForEach w porównaniu z równoważną instrukcją foreach dla potoku foreach-Object są zdecydowanie mile widzianym ulepszeniem. Z tym wyjaśnieniem na uboczu, przejdźmy do metody Where.

metoda Where

Where jest metodą umożliwiającą filtrowanie kolekcji obiektów. Jest to bardzo podobne do polecenia Where-Object, ale metoda Where jest również podobna do Select-Object i Group-Object, zawiera kilka dodatkowych funkcji, których polecenie Where-Object nie obsługuje samodzielnie. Metoda ta zapewnia szybszą wydajność niż Where-Object w prostym, eleganckim poleceniu. Podobnie jak metoda ForEach, wszystkie obiekty, które są wyprowadzane przez tę metodę, są zwracane w ogólnym zbiorze typu System.Kolekcje.ObjectModel.Kolekcja1.

istnieje tylko jedna wersja tej metody, którą można opisać następująco:

Where(scriptblock expression])

jak wskazano w nawiasach kwadratowych, wymagany jest blok skryptu wyrażenia, a wyliczenie trybu i argument liczby całkowitej numberToReturn są opcjonalne, więc można wywołać tę metodę za pomocą 1, 2 lub 3 argumentów. Jeśli chcesz użyć konkretnego argumentu, musisz podać wszystkie argumenty po lewej stronie tego argumentu(tzn. jeśli chcesz podać wartość dla numberToReturn, musisz podać również wartości dla mode i expression).

Where(wyrażenie scriptblock)

najbardziej podstawowe wywołanie metody Where po prostu pobiera wyrażenie bloku skryptu jako argument. Wyrażenie bloku skryptowego zostanie obliczone jednorazowo dla każdego obiektu w przetwarzanej kolekcji, a jeżeli zwróci wartość true, obiekt zostanie zwrócony przy pomocy metody Where. Jest to funkcjonalny odpowiednik wywołania polecenia Where-Object i przekazania mu bloku skryptu. Podobnie jak w przypadku polecenia Where-Object, zmienne $_ i $PSItem mogą być użyte do odniesienia do bieżącego elementu, który jest przetwarzany wewnątrz bloku skryptów.

oto bardzo prosty przykład, pokazujący, w jaki sposób można uzyskać listę uruchomionych usług.

# Get all services$services = Get-Service# Now filter out any services that are not running$services.where{$_.Status -eq 'Running'}

To nie oferuje żadnej nowej funkcjonalności, ale oferuje znacznie szybszą wydajność niż Where-Object, a składnia jest dość łatwa do naśladowania, więc naprawdę powinieneś wziąć to pod uwagę w swoich skryptach, gdy wykonujesz filtrowanie po stronie klienta kolekcji, które zapisałeś w zmiennej.

Where(scriptblock expression, WhereOperatorSelectionMode mode)

gdy zaczniesz przeglądać parametry opcjonalne dla metody Where, wszystko zaczyna być o wiele ciekawsze. Windows PowerShell w wersji 4.0 zawiera nowe wyliczenie z nazwą typu systemu.Zarządzanie.Automatyzacja.Gdzieoperatorselectionmode. Zwróć uwagę na przyrostek nazwy typu: „SelectionMode”. Służy do zapewnienia potężnych możliwości wyboru w składni Where. Oto wartości zawarte w tym wyliczeniu, wraz z ich definicjami:

domyślne Filtruj kolekcję za pomocą bloku skryptu wyrażenia, do maksymalnej liczby, jeśli jeden został dostarczony lub domyślnie dla wszystkich obiektów w kolekcji, jeśli nie podano maksymalnej liczby w numbertoreturn.
pierwszy zwraca pierwsze N obiektów, które przechodzą przez filtr bloku skryptów wyrażeń, domyślnie tylko 1 obiekt, jeśli w numberToReturn nie żądano określonej liczby.
Last zwraca N ostatnich obiektów, które przekazują filtr bloku skryptu wyrażenia, domyślnie tylko 1 obiekt, jeśli nie żądano określonej liczby w numberToReturn.
SkipUntil pomija obiekty w kolekcji, aż obiekt przejdzie filtr bloku skryptu wyrażenia, a następnie zwróci pierwsze N obiektów, domyślnie do wszystkich pozostałych obiektów, jeśli w numberToReturn Nie podano maksymalnej liczby.
Until zwraca pierwsze N obiektów w kolekcji, dopóki obiekt nie przejdzie przez filtr bloku skryptu wyrażenia, domyślnie wszystkie obiekty prowadzące do pierwszego obiektu, który przeszedł, jeśli w numberToReturn Nie podano maksymalnej liczby.
podziel podziel kolekcję na dwie części, umieszczając wszystkie obiekty, które przekazują filtr bloków skryptu wyrażeń do pierwszej kolekcji do maksymalnej liczby, jeśli jeden został podany w numberToReturn, lub wszystkie obiekty, które przechodzą, jeśli nie podano maksymalnej liczby, i umieszczając wszystkie inne obiekty, które nie są umieszczone w pierwszej kolekcji do drugiej kolekcji.

każdy z nich oferuje pewną unikalną wartość podczas przetwarzania zbiorów danych, więc podam więcej szczegółów na temat każdego trybu wyboru poniżej.

Default

nic dziwnego, że domyślną wartością argumentu mode jest 'Default’. Domyślny tryb wyboru oferuje te same funkcje, które są dostępne, gdy w ogóle go nie udostępniasz. Na przykład, mogliśmy napisać ostatnią linijkę naszego poprzedniego przykładu w ten sposób:

# Now filter out any services that are not running$services.where({$_.Status -eq 'Running'},'Default')

w tym przykładzie dodatkowy argument nie jest jednak konieczny, ponieważ robi dokładnie to samo, co zrobiłby, gdybyś go nie podał. Możesz również podać maksymalną liczbę obiektów, które chcesz zwrócić podczas korzystania z domyślnego trybu wyboru za pomocą argumentu numberToReturn, jak ten:

# Get the first 10 services in our collection that are running$services.where({$_.Status -eq 'Running'},'Default',10)

ważne jest, aby pamiętać, że dokładna funkcjonalność jest również dostępna podczas korzystania z pierwszego trybu wyboru (o którym porozmawiamy za chwilę), więc tak naprawdę nie jest praktyczne używanie żadnego z opcjonalnych parametrów podczas korzystania z domyślnego trybu wyboru.

pierwszy

jak można się domyślić, pierwszy tryb selekcji pozwala na zaznaczenie pierwszych obiektów w kolekcji, które przechodzą przez filtr wyrażenia bloku skryptu. Jeśli użyjesz First bez wartości dla argumentu numberToReturn lub jeśli użyjesz First z wartością 0 dla argumentu numberToReturn, zostanie zwrócony tylko pierwszy obiekt, który przejdzie przez filtr. Opcjonalnie można określić, ile obiektów ma zostać zwróconych w argumencie numberToReturn, w którym to przypadku zostanie zwróconych wiele obiektów (zakładając, że jest tak wiele obiektów, które przechodzą przez filtr).

oto kilka przykładów korzystania z naszej kolekcji usług pokazujących pierwszy tryb wyboru w działaniu:

# Get the first service in our collection that is running$services.where({$_.Status -eq 'Running'},'First')# Get the first service in our collection that is running$services.where({$_.Status -eq 'Running'},'First',1)# Get the first 10 services in our collection that are running$services.where({$_.Status -eq 'Running'},'First',10)

zauważ, że drugie polecenie w tych przykładach zwraca takie same wyniki jak pierwsze polecenie, ponieważ po prostu jawnie przekazuje domyślną wartość argumentu numberToReturn, gdy używany jest pierwszy tryb wyboru.

Last

tryb ostatniego wyboru działa podobnie jak tryb pierwszego wyboru, pozwalając na zaznaczenie ostatnich obiektów w kolekcji, które przechodzą przez filtr wyrażenia bloku skryptu. Gdy użyjesz Last bez wartości dla argumentu numberToReturn lub gdy użyjesz Last z wartością 0 dla argumentu numberToReturn, zostanie zwrócony tylko ostatni obiekt, który przejdzie przez filtr. Opcjonalnie można określić, ile obiektów ma zostać zwróconych w argumencie numberToReturn, w którym to przypadku zostanie zwróconych wiele obiektów (zakładając, że jest tak wiele obiektów, które przechodzą przez filtr).

oto kilka przykładów korzystania z naszej kolekcji usług pokazujących ostatni tryb wyboru w akcji:

# Get the last service in our collection that is running$services.where({$_.Status -eq 'Running'},'Last')# Get the last service in our collection that is running$services.where({$_.Status -eq 'Running'},'Last',1)# Get the last 10 services in our collection that are running$services.where({$_.Status -eq 'Running'},'Last',10)

podobnie jak w przypadku pierwszego trybu selekcji, drugie polecenie w tych przykładach zwraca te same wyniki co pierwsze polecenie, ponieważ po prostu jawnie przekazuje domyślną wartość argumentu numberToReturn, gdy używany jest ostatni tryb selekcji.

SkipUntil

tryb wyboru SkipUntil pozwala na pominięcie wszystkich obiektów w kolekcji, dopóki nie znajdziesz takiego, który przejdzie przez filtr wyrażenia bloku skryptu. Po znalezieniu obiektu, który przechodzi przez Filtr, Tryb SkipUntil zwróci wszystkie obiekty pozostałe w kolekcji, jeśli do argumentu numberToReturn Nie podano wartości lub wartość 0, lub zwróci pierwsze N pozostałych obiektów w kolekcji, jeśli do argumentu numberToReturn podano wartość większą niż zero. W obu przypadkach wyniki będą zawierać pierwszy obiekt, który przeszedł filtr.

oto kilka przykładów użycia podzbioru naszej kolekcji usług, aby pokazać tryb wyboru SkipUntil w działaniu:

# Get a collection of services whose name starts with "c"$services = Get-Service c*# Skip all services until we find one with a status of "Running"$services.where({$_.Status -eq 'Running'},'SkipUntil')# Skip all services until we find one with a status of "Running", then# return the first 2$services.where({$_.Status -eq 'Running'},'SkipUntil',2)

Until

tryb wyboru Until zapewnia odwrotną funkcjonalność trybu wyboru SkipUntil. Pozwala na zwracanie obiektów w kolekcji, dopóki nie znajdziesz takiego, który przejdzie przez filtr wyrażenia bloku skryptowego. Po znalezieniu obiektu, który przechodzi przez filtr, metoda Where zatrzymuje przetwarzanie obiektów. Jeśli nie podasz wartości argumentu numberToReturn lub jeśli podasz wartość 0, tryb wyboru Until zwróci wszystkie obiekty w kolekcji poprzedzające pierwszy, który przekazuje filtr wyrażenia bloku skryptowego. Jeśli podasz wartość argumentu numberToReturn większą niż 0, tryb wyboru Until zwróci co najwyżej tę liczbę obiektów, co oznacza, że może nawet nie znaleźć obiektu przekazującego filtr wyrażenia bloku skryptowego.

oto kilka przykładów użycia innego podzbioru naszej kolekcji usług, aby pokazać tryb wyboru Until w akcji:

# Get a collection of services whose name starts with "p"$services = Get-Service p*# Return all services until we find one with a status of "Stopped"$services.where({$_.Status -eq 'Stopped'},'Until')# Return the first 2 services unless we find one with a status of# "Stopped" first$services.where({$_.Status -eq 'Stopped'},'Until',2)

Split

Split selection mode jest unikalny. Zamiast zwracać podzbiór kolekcji, od której zaczynasz w nowej kolekcji, zwraca ona nową kolekcję, która wewnętrznie zawiera dwa oddzielne Kolekcje. Zawartość tych zagnieżdżonych kolekcji zależy od sposobu korzystania z trybu selekcji podzielonej. Split pozwala podzielić kolekcję obiektów na dwie części. Domyślnie, jeśli nie podasz wartości dla argumentu numberToReturn lub jeśli podasz wartość 0 dla argumentu numberToReturn, Split umieści wszystkie obiekty, które przekazują filtr wyrażenia bloku skryptowego do pierwszej zagnieżdżonej kolekcji, a wszystkie inne obiekty (te, które nie przekazują filtra wyrażenia bloku skryptowego) do drugiej zagnieżdżonej kolekcji. Jeśli podasz wartość większą niż 0 dla argumentu numberToReturn, split ograniczy rozmiar pierwszej kolekcji do tej maksymalnej ilości, a wszystkie pozostałe obiekty w kolekcji, nawet te, które pasują do filtra wyrażenia bloku skryptowego, zostaną umieszczone w drugiej kolekcji.

oto kilka przykładów pokazujących, w jaki sposób można podzielić zbiór obiektów na różne sposoby:

# Get all services$services = Get-Service# Split the services into two groups: Running and not Running$running,$notRunning = $services.Where({$_.Status -eq 'Running'},'Split')# Show the Running services$running# Show the services that are not Running$notRunning# Split the services into the same two groups, but limit the Running group# to a maximum of 10 items$10running,$others = $services.Where({$_.Status -eq 'Running'},'Split',10)# Show the first 10 Running services$10running# Show all other services$others

Jak widać w tym przykładzie, Split jest dość potężnym trybem selekcji, zapewniającym mieszankę filtrowania, grupowania i selekcji w jednym wywołaniu polecenia.

Ten zbiór trybów wyboru sprawia, że metoda Where jest szybka i elegancka, a jednocześnie potężniejsza niż Where-Object, Group-Object i Select-Object połączone w jednym potoku. Czego tu nie kochać?

niedociągnięcia w foreach i gdzie metody Skryptowe w TypePx

jak wspomniałem wcześniej w tym artykule, napisałem rozszerzenia typów dla PowerShell 3.0 i Później i spakował je do modułu o nazwie TypePx. TypePx jest modułem skryptowym, który został napisany w całości w PowerShell i działa na PowerShell 3.0 lub nowszym. Jeśli używasz PowerShell 3.0 (i tylko jeśli używasz PowerShell 3.0), TypePx definiuje ForEach i Where metody Skryptowe, które naśladują zachowanie ForEach i Where metody w PowerShell 4.0 i nowszych. Podczas gdy rozszerzony system typów w PowerShell umożliwia naśladowanie tego zachowania, istnieje kilka niedociągnięć ze względu na implementację w PowerShell, która wpłynęła na to, jak daleko byłem w stanie posunąć się z tymi rozszerzeniami typów. W tej sekcji opiszemy niektóre różnice i ograniczenia istniejące w ForEach oraz metody Skryptowe Where w TypePx, o których warto wiedzieć, jeśli używasz PowerShell 3.0.

bloki skryptów wywoływane z metody skryptowej uruchamiane w zakresie potomnym

W Przeciwieństwie Do ForEach i gdzie metody zaimplementowane jako część PowerShell 4.0 lub nowsze, które wywołują blok skryptu wyrażenia w bieżącym zakresie, w którym metoda jest wywoływana, ForEach i gdzie metody Skryptowe zaimplementowane w PowerShell 3.0 wywołują blok skryptu wyrażenia w zakresie potomnym. Jest to ograniczenie w PowerShell, które istnieje od samego początku (ograniczenie, Mogę dodać, że moim zdaniem jest zdecydowanie największym mankamentem PowerShell jako języka).

z powodu tego ograniczenia, wszelkie zmienne przypisane do bloku skryptu wyrażenia będą modyfikowane tylko w zakresie potomnym. Ma to wpływ na to, czy blok skryptu wyrażenia ma na celu aktualizację zmiennej w zakresie, w którym wywołujesz ForEach lub gdzie. Jest mało prawdopodobne, że spowodowałoby to problem podczas używania Where, ponieważ nie jest bardzo często modyfikowanie zmiennych w bloku skryptu wyrażenia where, ale w blokach skryptów foreach może to stanowić problem, więc musisz o tym pamiętać, jeśli używasz tych rozszerzeń.

powinienem zauważyć, że chciałbym całkowicie usunąć to ograniczenie i wierzę, że będę w stanie to zrobić, jednak w momencie pisania tego artykułu nie wdrożyłem jeszcze poprawki do tego.

Większość, ale nie wszystkie kolekcje będą miały foreach i Where metody

w PowerShell 4.0 i nowszych, foreach i Where metody są magicznie dostępne dla wszystkich typów, które implementują IEnumerable z wyjątkiem String, XmlNode i typów, które implementują IDictionary. W PowerShell, rozszerzony system typów nie pozwala na tworzenie rozszerzeń dla interfejsów, tylko dla typów. Jest to wyzwanie, jeśli chcesz utworzyć szerokie rozszerzenie, takie jak ForEach i Where. W bieżącej implementacji tych rozszerzeń w TypePx moduł TypePx znajduje Wszystkie typy we wszystkich złożeniach załadowanych w bieżącej domenie aplikacji, a dla wszystkich niesterydowych typów, które definiują IEnumerable, ale nie IDictionary (z wyjątkiem String i XmlNode), plus dla wszystkich typów generycznych, które definiują IEnumerable, ale nie IDictionary dla ogólnych kolekcji PSObject, Object, String, Int32 lub Int64, zostaną utworzone metody foreach i Where script.

obejmuje to dużą liczbę typów, które w moich własnych testach były wystarczające, jednak możesz napotkać typy, w których chcesz użyć tych metod i nie są one dostępne. Jeśli tak jest, Daj mi znać przez GitHub, a zobaczę, co mogę zrobić. Jest to również ograniczenie, które chciałbym usunąć, ale potrzebuję więcej czasu na zbadanie, jak zaimplementować równoważną funkcjonalność w skompilowanym zespole, gdzie mogę być w stanie zdefiniować ją bardziej tak, jak jest zdefiniowana w PowerShell 4.0 i późniejszych.

skrypty PowerShell nie są tak szybkie jak skompilowany kod

to chyba oczywiste, ale kiedy piszesz coś w PowerShell, który jest językiem interpretowanym, nie będzie działać tak szybko, jak gdybyś napisał równoważną logikę w języku takim jak C#. Tak jest w przypadku metod skryptowych ForEach i Where, które wewnętrznie używają ForEach-Object, Where-Object i pipelining do naśladowania zachowania natywnych metod ForEach i Where. W tym przypadku zaletą posiadania tych poleceń jest elegancka składnia i funkcjonalność, które zapewniają, a także możliwość korzystania z nich w skryptach dla PowerShell 3.0 i 4.0. Korzyści z wydajności w ForEach i Where są tylko w natywnej implementacji PowerShell 4.0.

PowerShell 3.0 wymaga nawiasów wokół wszystkich parametrów metody

wspomniałem w powyższych przykładach, że byłem w stanie wywołać metodę z jednym parametrem bloku skryptu bez owijania tego bloku skryptu w dodatkowe nawiasy. Ta możliwość istnieje tylko w PowerShell 4.0 lub później ze względu na ulepszenia, które zostały wprowadzone do parsera w tym wydaniu. W PowerShell 3.0, parser nie obsługuje tego, więc nawiasy są zawsze wymagane, aby metody Skryptowe ForEach i Where działały z pojedynczym parametrem bloku skryptu w tej wersji.

podsumowanie

Kiedy zacząłem próbować naśladować zachowanie ForEach i gdzie magiczne metody w PowerShell 3.0, nie do końca zdawałem sobie sprawę, ile funkcjonalności zapewniają. Zagłębianie się w szczegóły techniczne tych metod, abym mógł stworzyć rozszerzenia, które chciałem w TypePx, pomogło odkryć wszystkie ukryte funkcje tych bardzo potężnych metod i jestem bardzo szczęśliwy, że mogę podzielić się nimi z wami w tym artykule. Mam nadzieję, że te informacje pomogą Ci wykorzystać ten wspaniały nowy zestaw funkcji w pracy PowerShell, nawet jeśli nadal używasz PowerShell 3.0. Miłego skryptowania!