Adam the Automator

author
13 minutes, 34 seconds Read

Kiedy piszesz skrypt PowerShell bez funkcji i bez zewnętrznych zależności od innych skryptów, koncepcja zakresów PowerShell nie jest zbyt istotna. Koncepcja zmiennych globalnych PowerShell nie jest przednia i centralna. Ale gdy zaczynasz budować funkcje, moduły i uczysz się wywoływać skrypty z innych skryptów, temat ten staje się coraz ważniejszy.

W tym artykule otrzymasz głęboką lekcję tego, czym są zakresy w PowerShell, jak działają i jak możesz pisać kod z myślą o zakresach. Zanim skończysz, zrozumiesz zmienne globalne PowerShella i wiele więcej!

Table of Contents

Scopes: Kinda Like Buckets

Czy kiedykolwiek napisałeś skrypt, w którym zdefiniowałeś zmienną, a kiedy sprawdzasz wartość tej zmiennej, jest ona czymś innym? Możesz drapać się w głowę, jak ta zmienna się zmieniła, gdy ją wyraźnie zdefiniowałeś. Jednym z powodów może być to, że wartość zmiennej jest nadpisywana w innym zakresie.

Może zastanawiałeś się, w jaki sposób niektóre zmienne PowerShell mają wartości, gdy odwołujesz się do nich w konsoli, ale nie istnieją w twoich skryptach. Możliwe, że te zmienne znajdują się w innym „wiadrze”, które nie jest dostępne w tym czasie.

Zakresy są jak wiadra. Zakresy wpływają na sposób, w jaki PowerShell izoluje zmienne, aliasy, funkcje i PSDrive’y pomiędzy różnymi obszarami. Zakres jest jak wiadro. Jest to miejsce, w którym wszystkie te elementy są gromadzone razem.

Gdy PowerShell startuje, automatycznie tworzy dla ciebie te „wiadra”. W tym momencie używasz już zakresów, nie zdając sobie z tego sprawy. Wszystkie zakresy są definiowane przez PowerShell i są tworzone bez żadnej pomocy z twojej strony.

Typy zakresów

Gdy PowerShell się uruchamia, automatycznie tworzy cztery „wiadra” lub zakresy, w których można umieścić różne elementy. Nie można samodzielnie tworzyć zakresów. Można jedynie dodawać i usuwać elementy z tych zakresów zdefiniowanych poniżej.

Zakres globalny

Przedmioty zdefiniowane podczas uruchamiania PowerShella są ustawiane w zakresie globalnym. Te elementy obejmują obiekty utworzone przez system, takie jak dyski PowerShell, a także wszystko, co zostało zdefiniowane w profilu PowerShell, ponieważ profil jest uruchamiany przy starcie.

Przedmioty z zakresu globalnego są dostępne wszędzie. Możesz odwoływać się do elementów z zakresu globalnego interaktywnie na konsoli, w każdym uruchomionym skrypcie i w każdej funkcji. Zmienne globalne w PowerShell są wszędzie. Z tego powodu powszechnym zastosowaniem zmiennych globalnych PowerShell jest używanie zmiennych globalnych PowerShell między skryptami.

Istnieje tylko jeden zakres globalny, który rządzi ogółem.

Zakres skryptu

Zakres skryptu jest automatycznie tworzony przy każdym uruchomieniu skryptu PowerShell. Można mieć wiele różnych instancji zakresu skryptu. Zakresy skryptów są tworzone podczas wykonywania skryptu PS1 lub modułu, na przykład.

Tylko elementy utworzone w tej konkretnej instancji zakresu skryptu mogą odwoływać się do siebie nawzajem.

Zakres prywatny

Typowo, zdefiniowany element może być dostępny z innych zakresów – nie jest to prawdą w przypadku elementów w zakresie prywatnym. Elementy w zakresie prywatnym zawierają obiekty, które są ukryte dla innych zakresów. Zakres prywatny jest używany do tworzenia elementów o tej samej nazwie, co elementy w innych zakresach, aby zapobiec nakładaniu się.

Zakres lokalny

W przeciwieństwie do innych zakresów, zakres lokalny jest nieco inny. Zakres lokalny jest wskaźnikiem do zakresu globalnego, skryptowego lub prywatnego. Zakres lokalny jest względny do dowolnego kontekstu, w którym działa kod w danym momencie.

Jeśli utworzysz zmienną, alias, funkcję lub PSDrive bez jawnego przypisania jej zakresu (co omówimy później), trafi ona do zakresu lokalnego.

Odwołania do zakresów

Teraz, gdy masz pojęcie o czterech typach zakresów, które istnieją, powinieneś również wiedzieć, że istnieją dwa sposoby odwoływania się do tych zakresów.

W PowerShell istnieją dwa sposoby odwoływania się do zakresów – nazwane lub numerowane. Obie metody odwołują się do tych samych zakresów, ale po prostu w inny sposób. Są to dwa różne sposoby interakcji z zakresami.

Zakresy nazwane

Powyżej, w sekcji Typ zakresu, dowiedziałeś się o zakresach, do których odwołujesz się przez nazwę. Odwoływanie się do zakresu przez nazwę jest, intuicyjnie, nazywane zakresem nazwanym. Głównym celem odwoływania się do zakresu przez nazwę jest przypisanie elementu do zakresu. Jak to zrobić, dowiesz się poniżej.

Zakresy numerowane

Wraz z nazwą, każdy zakres ma numer zaczynający się od zera, który zawsze będzie zakresem lokalnym. Zakresy są numerowane dynamicznie w stosunku do bieżącego zakresu lokalnego.

Na przykład, gdy tylko otworzysz sesję PowerShell, działasz w zakresie globalnym. W tym momencie zakres globalny jest zakresem lokalnym (pamiętaj, że zakres lokalny jest tylko wskaźnikiem).

Ponieważ zakres lokalny jest zawsze zakresem zerowym, w tym momencie zakres globalny jest również obecnie zakresem zerowym. Ale kiedy uruchamiasz skrypt z tej samej sesji, tworzony jest zakres skryptu. Podczas uruchamiania lokalny wskaźnik zakresu został zmieniony na zakres skryptu. Teraz zakres skryptu jest zakresem zerowym, a zakres globalny jest zakresem pierwszym.

Zakresy są numerowane Ten proces powtarza się dla tylu zakresów, ile masz, gdzie zakres lokalny jest 0. Zakresy są dynamicznie numerowane przez hierarchię zakresów.

Hierarchia zakresów i dziedziczenie

Jak wspomniano wcześniej, gdy uruchamiasz sesję PowerShell, PowerShell tworzy dla Ciebie pewne elementy w zakresie globalnym. Elementy te mogą być funkcjami, zmiennymi, aliasami lub PSDrives. Wszystko, co zdefiniujesz w sesji PowerShell, zostanie również zdefiniowane w zakresie globalnym.

Ponieważ domyślnie znajdujesz się w zakresie globalnym, jeśli zrobisz coś, co tworzy inny zakres, jak wykonanie skryptu lub uruchomienie funkcji, zostanie utworzony zakres dziecięcy, którego rodzicem będzie zakres globalny. Zakresy są jak procesy z rodzicami i dziećmi.

Wszystko, co jest zdefiniowane w zakresie rodzica, zakres globalny, w tym przypadku, będzie dostępne w zakresie dziecka. Ale te elementy są edytowalne tylko w zakresie, w którym zostały zdefiniowane.

Powiedzmy, że masz skrypt o nazwie Test.ps1. Wewnątrz tego skryptu znajduje się pojedyncza linia, jak pokazano poniżej.

$a = 'Hello world!'

Gdy uruchamiasz ten skrypt, $a jest przypisywana wartość w zakresie lokalnym (skrypt, gdy skrypt jest uruchomiony). Kiedy Test.ps1 jest uruchamiany, możesz zobaczyć poniżej, że nie jesteś w stanie odwołać się do niego po wykonaniu skryptu. Ponieważ $a została przypisana w zakresie skryptu, zakres globalny (w konsoli interaktywnej) nie może jej zobaczyć.

Zakres globalny nie może zobaczyć zmiennej

Pójdźmy w tym przykładzie o krok dalej i sprawmy, aby skrypt Test.ps1 wyglądał jak poniżej. Skrypt próbuje teraz wyprowadzić wartość $a przed ustawieniem jej w tym samym zakresie.

Write-Output $a$a = 'Hello world!'

Aby zademonstrować, przypisz wartość do $a w konsoli interaktywnej. To przypisuje wartość w zakresie globalnym. Teraz, skrypt uruchomiony, będzie dziedziczył zakres nadrzędny (globalny) i powinien być w stanie zobaczyć wartość.

Możesz zobaczyć poniżej, że kiedy Test.ps1 jest wykonywany (tworząc zakres dziecka zakresu globalnego), może zobaczyć wartość $a. Możesz również zobaczyć, że wartość zmiennej jest dostępna w globalnym zakresie, ponieważ jest to zakres, w którym została ona ustawiona. Oznacza to, że $a jest dostępna zarówno w zakresie skryptu (child) jak i rodzica (global).

Zmienna jest dostępna w zakresie skryptu i globalnym

Zapamiętaj to zachowanie dziedziczenia zakresu. Pomoże to w rozwiązywaniu problemów, gdy wystąpią konflikty zmiennych, takie jak zmienne w różnych zakresach o tej samej nazwie.

Definiowanie i dostęp do elementów w zakresach

Teraz, gdy już wiesz, czym jest zakres i jak działa, jak uzyskać do nich dostęp? Zobaczmy, jak użyć PowerShell do ustawienia zakresu zmiennych (i dostępu do nich).

Get/Set-Variable

W PowerShell istnieją dwa cmdlety, które pozwalają na ustawienie zmiennych o nazwach Get-Variable i Set-Variable. Te polecenia cmdlet pozwalają pobrać wartość zmiennej lub zdefiniować wartość.

Oba polecenia cmdlet są podobne z parametrem Name i Scope. Używając tych parametrów, PowerShell pozwala na ustawianie i pobieranie wartości zmiennych we wszystkich zakresach.

Zakresy lokalne

Aby ustawić zmienną w zakresie lokalnym, należy użyć Set-Variable i podać jej nazwę zmiennej lokalnej oraz wartość, jak pokazano poniżej.

PS> Set-Variable -Name a -Value 'foo'

Zakres lokalny jest zawsze domyślny, więc nieużycie parametru Scope zawsze zdefiniuje zmienną w zakresie lokalnym.

Aby pobrać wartość zmiennej o zasięgu lokalnym, użyj Get-Variable podając jej nazwę.

PS> Get-Variable -Name aName Value---- -----a foo

Zakresy prywatne/skryptowe/globalne

Tych samych parametrów (Name i Value) użyjesz również podczas pracy ze zmiennymi prywatnymi, skryptowymi i globalnymi. Jedyna różnica polega na tym, że tym razem użyjesz parametru Scope, aby jawnie określić zakres.

Metody ustawiania zmiennej prywatnej, skryptowej lub globalnej są takie same. Po prostu zamień wartość przekazaną do parametru Scope na Private, Script Global.

PS> Set-Variable -Name a -Value 'foo' -Scope <Private|Script|Global>

Aby pobrać wartość skryptu lub zmiennej globalnej, użyj Get-Variable podając jej nazwę i zakres.

PS> Get-Variable -Name a -Scope <Script|Global>Name Value---- -----a foo

Uwaga: Można również odwoływać się do zakresów, używając numerów zakresów zamiast nazw za pomocą cmdletów Get/Set-Variable.

Zakres „Prefacing”

Można również pobierać i ustawiać zmienne w zakresach, używając skrótu. Zamiast używać cmdletów PowerShell, będziesz poprzedzać zakres do zmiennej podczas odwoływania się do niej.

Zakresy lokalne

Ponieważ zakres lokalny jest zawsze domyślny, proste zdefiniowanie zmiennej i odwołanie się do niej ustawi i pobierze zmienną zakresu lokalnego

PS> $a = 'foo'PS> $afoo

Zakresy prywatne/skryptowe/globalne

Jeśli chcesz zdefiniować i odwołać się do zakresów skryptowych lub globalnych, możesz poprzedzić zmienne nazwą zakresu i średnikiem.

Na przykład, aby ustawić zmienną $a w zakresie globalnym, możesz poprzedzić a za pomocą $global:.

$global:a = 'foo'

To samo można zrobić dla zmiennej dotyczącej skryptu.

$script:a = 'foo'

Jak tylko zmienne zostaną ustawione w preferowanym zakresie, odwołasz się do nich w ten sam sposób. Zauważ również, że możesz wykluczyć przedmowę zakresu, jeśli zdefiniowany zakres jest zakresem lokalnym.

PS> $global:a = 'foo'PS> $global:afooPS> $afoo

Zakresy w blokach skryptów

PowerShell ma poręczną konstrukcję zwaną blokami skryptów. Bloki skryptów pozwalają na poruszanie się wokół fragmentów kodu i wykonywanie ich w dowolnym miejscu.

Podobnie jak skrypty PS1, bloki skryptów działają we własnym zakresie skryptu. Kiedy wykonujesz scriptblock, w zasadzie wykonujesz skrypt PS1.

Zauważ w poniższym przykładzie, gdzie zmienna jest zdefiniowana w globalnym zakresie, a następnie próbuje się ją nadpisać w zakresie skryptu. Jak dowiedziałeś się powyżej, to nie zadziała, ponieważ zakres dziecięcy nie może odwoływać się do zakresu nadrzędnego.

Zakres dziecięcy nie może nadpisać zakresu nadrzędnego

Ten przykład pokazuje, że gdy $a jest zmieniany w bloku skryptu, definicja zmiennej globalnej dla $a nie jest zmieniana, ponieważ blok skryptu jest zakresem dziecięcym skryptu.

Dot Sourcing skryptów (zamiana zakresów lokalnych)

PowerShell ma koncepcję zwaną dot-sourcing. Jest to metoda, która pozwala na wykonanie skryptu PS1 i przeniesienie wszystkiego, co byłoby przypisane do skryptu, do zakresu lokalnego.

Poprzez postawienie kropki (.) przed odwołaniem do skryptu PS1 i jego wykonaniem, to „źródło kropek” zawartości skryptu i przeniesienie wszystkiego do zakresu lokalnego.

Aby zademonstrować, mam skrypt Test.ps1, który definiuje zmienną, jak pokazano poniżej.

$a = 'Hello world!'

W konsoli PowerShell ustaw wartość zmiennej $a, a następnie wykonaj dot source tego skryptu, jak pokazano poniżej. Zauważ, że oryginalna zmienna została nadpisana. PowerShell „połączył” dwa lokalne zakresy razem.

Oryginalna zmienna nadpisana

Używanie właściwości AllScope (opcja)

Widziałeś, jak oddziaływać z elementami w określonych zakresach, ale jak dotąd każdy element jest nadal zdefiniowany w pojedynczym zakresie. Ale co zrobić, jeśli nie wiesz, w jakim zakresie zdefiniowana jest zmienna?

Podczas definiowania zmiennej za pomocą cmdletu Set-Variable możesz umieścić zmienną we wszystkich zakresach jednocześnie. Aby to zrobić, należy użyć wartości AllScope dla parametru Option.

Aby zademonstrować, skrypt Test.ps1 został zmodyfikowany w celu ustawienia zmiennej we wszystkich zakresach. Ta zmienna jest następnie wyprowadzana, jak pokazano poniżej.

Set-Variable -Name a -Value 'Hello world!' -Option AllScopeWrite-Output $a

Można więc zobaczyć poniżej, że wartość jest ustawiana dla $a w zakresie globalnym, a skrypt Test.ps1 jest wykonywany. Jednakże, zamiast nie mieć żadnego efektu, wartość $a została nadpisana. Nie tylko została ona zdefiniowana w zakresie skryptu (Write-Output $a), ale także nadpisana w zakresie globalnym.

Zmienna nadpisana w zakresie globalnym

Opcja AllScope jest przydatna, ale należy zachować ostrożność. Ta opcja zasadniczo usuwa koncepcję zakresów i łączy wszystko razem.

Zakresy funkcji

Gdy wykonujesz funkcję, cały kod wewnątrz tej funkcji jest w jej własnym zakresie dziecka. Zakresy funkcji zachowują się tak samo jak inne zakresy.

Mienie oddzielnych zakresów dla każdej funkcji jest dobrym pomysłem. Pozwala to na lepszą kontrolę nad elementami, nie musząc się martwić o konflikty elementów, Daje to również dodatkową korzyść w postaci automatycznego czyszczenia zmiennych w funkcji. Gdy tylko funkcja się zakończy, wszystkie elementy zdefiniowane w funkcji zostaną wyczyszczone.

Aby zademonstrować, skopiuj/wklej poniższą funkcję bezpośrednio do konsoli PowerShell.

Function Do-Thing { $var = 'bar'}

Po wklejeniu wykonaj funkcję. Zauważ, że nie możesz uzyskać dostępu do zmiennej $var poza funkcją.

PS> Do-ThingPS> $var

Utrzymywanie elementów w stanie prywatnym (wyłączanie dziedziczenia)

Typowo, jeśli zmienna jest zdefiniowana w zakresie rodzica, ta zmienna będzie zdefiniowana w zakresie dziecka. Ale być może chciałbyś użyć nazwy zmiennej, ale ta nazwa zmiennej została już zdefiniowana w jednym z zakresów, które mają być uruchomione w sesji. W takim przypadku możesz wybrać inną nazwę zmiennej lub zdefiniować zmienną w zakresie prywatnym, czyniąc ją zmienną prywatną.

Sposobem na użycie zakresów w celu zmniejszenia konfliktów jest użycie zakresu prywatnego. Użycie zakresu prywatnego wyłącza dziedziczenie na tej konkretnej zmiennej. Gdy zostanie utworzonych wiele zakresów potomnych, te zakresy nie będą widzieć żadnych zmiennych zdefiniowanych w prywatnym zakresie.

Skrypt Test.ps1 wypisuje wartość $a, jak pokazano poniżej.

Write-Output $a

Widać poniżej, że definiuję zmienną o prywatnym zakresie w zakresie globalnym, a następnie wykonuję skrypt Test.ps1. Zazwyczaj, gdy definiujesz zmienną w zakresie nadrzędnym, zmienna ta będzie dostępna w zakresie potomnym – nie jest tak w przypadku zmiennej o prywatnej domenie.

W poniższym przykładzie widać, że zakres dziecka skryptu utworzony przez wykonanie skryptu Test.ps1 nie mógł zobaczyć zmiennej o nazwie private-scoped $a zdefiniowanej w zakresie nadrzędnym.

Zakres skryptu nie może zobaczyć zmiennej o prywatnym zakresie

W przeciwieństwie do zakresów globalnych lub opcji AllScope w poleceniu Set-Variable, zmienne o prywatnym zakresie są doskonałym sposobem na podział elementów na przedziały.

Najlepsze praktyki w zakresie skalowania

Myślenie, że definiowanie zmiennych w zakresie globalnym lub używanie opcji AllScope jest drogą do zrobienia, jest powszechne. W końcu wszystkie zmienne są dostępne wszędzie. Nie ma potrzeby martwić się o komplikacje związane z zakresami. Chociaż zapewnia to dodatkową swobodę dostępu do tego, co zostało zdefiniowane, może szybko wymknąć się spod kontroli i utrudnić rozwiązywanie problemów.

Zamiast próbować zapobiegać używaniu zakresów, skorzystaj z następujących wskazówek:

  1. Zamiast określać zakresy w funkcjach, użyj parametrów, aby przekazać wymagane informacje do funkcji.
  2. Pozostań w lokalnym zakresie tak bardzo, jak to możliwe.
  3. Zamiast definiować zmienne globalne ze skryptu, użyj cmdletu Write-Output, aby wyprowadzić wszystko i zapisać do zmiennej, gdy jest to potrzebne z konsoli.

Głównym punktem jest przyjęcie zakresów i nauczenie się używania ich na swoją korzyść, zamiast próbowania ich obejścia.

Dalsze czytanie

  • O funkcjach zaawansowanych i parametrach funkcji
  • Używanie zmiennych środowiskowych w PowerShell

.

Similar Posts

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.