Powershell – efektywniej, część 8.

Zgodnie z obietnicą – w tej części zajmę się modułami. Czym są moduły w PowerShellu? Moduł to rozszerzenie. Może to być zarówno rozszerzenie binarne – w formie skompilowanej biblioteki dll, jak i skryptowe – w najbardziej podstawowej formie plik zawierający odpowiedni kod PowerShella z rozszerzeniem .psm1. Nas oczywiście interesować będzie moduł skryptowy.

Po co?

Czemu moglibyśmy chcieć stworzyć moduł? Moduły nadają się świetnie do zmieniania środowiska, pozwalają zebrać funkcje/ zmienne/ aliasy związane z jakimś zagadnieniem (np. obsługa lokalnych kont na stacjach roboczych; obsługa AD w danym, lokalnym OU). Moduł sprawdza się lepiej niż wrzucanie wszystkiego do profilu – dzięki temu kod staje się bardziej przenośny, a jeśli chcemy zmienić coś w zestawie funkcji dotyczących konkretnej technologii/ zagadnienia, to nie musimy ich szukać na piechotkę. Moduł pozwala też oddzielić elementy “prywatne” od “publicznych”. Ta izolacja pozwala uniknąć sytuacji, gdy dwa narzędzia będą ze sobą walczyć o jakąś zmienną. W ilu skryptach używamy gdzieś zmiennych typu $i, albo $sum(a)? No cóż, moduły mogą pracować w swoim wewnętrznym zakresie z dowolnymi, kolidującymi zmiennymi. Jeśli moduły nie “wypluwają” ich na zewnątrz (dojdziemy do tego jak to zrobić, domyślnie żadna zmienna nie wychodzi poza moduł) – do kolizji zmiennych nigdy nie dojdzie. Nie da się tego powiedzieć o dotsourcingu – tam zawartość skryptu wpada do naszego głównego zakresu, przez co możemy czasem wylać dziecko z kąpielą.

To wszystko?

Moduł to jednak dużo, dużo więcej. Kompletny moduł, oprócz tworzenia zestawu funkcji potrafi również:

  • zmieniać sposób wyświetlania obiektów
  • dodawać do istniejących/ definiowanych typów właściwości i metody skryptowe
  • tworzyć wielojęzyczną pomoc do naszego modułu
  • odpowiednio opisać metadane modułu (autora, wersję) – do tego służy manifest

Pierwsze dwa punkty realizowane są przy pomocy plików XML o specjalnej strukturze. Wszystkie pliki tego typu muszą mieć rozszerzenie .ps1xml. Ich stosowanie to jednak całkiem osobny temat. Poza tym takie modyfikacje przydają się zwykle w bardziej zaawansowanych modułach.

Pomoc dla modułu też raczej nie ma większego sensu jeśli tworzymy moduł w miarę prosty. Prosty moduł to zestaw funkcji, a funkcje można łatwo opisać posługując się pomocą w komentarzach. Oczywiście taka pomoc nie będzie wielojęzyczna, ale w przypadku, gdy z modułu nie będzie korzystało wielu ludzi – język nie jest istotną kwestią.

Ostatni punkt, czyli manifest, można w zasadzie zastosować do każdego modułu. Pomaga on śledzić wersje modułu, co z czasem może okazać się przydatne (gdy np. pracujemy na kilku komputerach i zechcemy moduł uaktualnić), informację o autorze, opis modułu… A ponieważ jego tworzenie nie jest bardzo skomplikowane (służy do tego cmdlet New-ModuleManifest), nic nie stoi na przeszkodzie, by moduł (nawet najprostszy) w taki manifest wyposażyć.

Tworzymy moduł: krok 1

Pierwszy krok to zebranie wszystkich funkcji, które nasz moduł ma udostępniać i zapisanie ich w pliku z odpowiednim rozszerzeniem. Taki moduł zwykle można od razu zacząć używać (wystarczy go zaimportować: Import-Module). Jeśli jednak chcemy by nasz moduł zawierał również funkcje pomocnicze (które nie powinny być widoczne na zewnątrz) bądź dodawał do sesji zmienne i aliasy (domyślnie wszystkie aliasy i zmienne definiowane w module nie są eksportowane poza moduł), musimy pójść krok dalej. Podstawowa metoda to wyeksportowanie “ręcznie” funkcji, zmiennych i aliasów. Trzeba jednak pamiętać, że eksportując dowolny element w ten sposób wyłączamy domyślny mechanizm eksportujący wszystkie funkcje z modułu. Popatrzmy na konkretny przykład, trzy proste moduły, bardzo podobne do siebie:

function Get-Foo { Write-Host foo }            
function pomoc { Write-Host Pomagam }            
New-Alias -Name foo -Value Get-Foo            
$Foo = 'Bar'            

Taki moduł udostępnia zarówno funkcję Get-Foo (która ma być widoczna) jak i funkcję pomoc – która w naszym przykładzie jest pomocnicza. Co jeśli dodamy Export-ModuleMember i zapomnimy o funkcjach…:

function Get-Foo { Write-Host foo }            
function pomoc { Write-Host Pomagam }            
New-Alias -Name foo -Value Get-Foo            
$Foo = 'Bar'            
            
Export-ModuleMember -Alias foo -Variable Foo

Alias ‘foo’ zadziała, ale skutkiem będzie błąd (funkcja Get-Foo nie będzie zdefiniowana, więc użyć się jej bezpośrednio nie da). Działać poprawnie będzie w zasadzie tylko zmienna $Foo. Prawidłowe użycie cmdletu Export-ModuleMember:

function Get-Foo { Write-Host foo }            
function pomoc { Write-Host Pomagam }            
New-Alias -Name foo -Value Get-Foo            
$Foo = 'Bar'            
            
Export-ModuleMember -Function Get-Foo -Alias foo -Variable Foo

Po zaimportowaniu tego modułu widoczna będzie tylko potrzebna nam funkcja (Get-Foo), alias, który do niej prowadzi (foo) oraz zmienna, którą chcemy zdefiniować ($Foo).

Tworzymy moduł: krok 2.

Zainicjowaliśmy więc moduł. Jak go testować? Import-Module działa jednorazowo, jeśli moduł w sesji już funkcjonuje – ponowny import nie da żadnego rezultatu. Na etapie tworzenia bardzo przydatny może się okazać parametr –Force – pozwala on zaimportować moduł wielokrotnie, dzięki czemu wprowadzone zmiany będą widoczne. Na etapie “produkcji” warto jest po każdej poważniejszej zmianie dokonać importu by przekonać się, czy nasz moduł nie przestał działać.

Warto też na tym etapie zastanowić się nad skutecznym mechanizmem, który polecenia i zmienne eksportowane z naszego modułu pozwoli wyróżnić. Prefiks ułatwi zarówno używanie modułu, jak i eksport poleceń/ zmiennych. Dlaczego? Otóż polecenie Export-ModuleMember obsługuje symbole wieloznaczne. Zamiast więc pojedynczo eksportować polecenia i zmienne – możemy na końcu modułu użyć:

Export-ModuleMember -Function *-Prefiks* -Variable Prefiks* -Alias *

Naturalnie, prefiks to raczej 2-3 literki. Puszczam oczko Gdzie zaś ułatwienie użytkowania? O ile prościej jest (posługując się TABem np.) dopełniać polecenie Get-Prefiks[TAB] zamiast przypominania sobie za każdym razem, jakich rzeczowników użyliśmy w naszych funkcjach? Get-Command –Module NaszModuł nieco sprawę upraszcza, ale nie wydaje mi się to najefektywniejszą metodą.

Co dalej?

W kolejnej części zamierzam opisać dokładniej manifest modułu i to, co on nam daje. Oprócz tego zamierzam napisać jak moduły przygotować do dystrybucji i jak “instalować” je, by zamiast składni: Import-Module .\Nazwa.psm1 móc skorzystać ze składni: Import-Module Nazwa. To w zasadzie drobiazg, ale myślę że warto o nim wspomnieć, na wypadek gdyby ktoś tego jednak nie wiedział… Puszczam oczko

~ - autor: Bartek Bielawski w dniu 17 grudnia, 2011.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Połączenie z %s

 
%d blogerów lubi to: