Skip to Content

IT nieuczesane.
category

Category: DevOps/Scripting

skrypty, programy, command line i inne

przekazywanie wartości – c.d.

jakiś czas temu pisałem o tym, jak powinno się/można przekazywać wartości via pipeline. krótki komentarz…

clue jest takie, że:

  • trzeba włączyć funkcje zaawansowane cmdletbinding()
  • użyć bloku ‚process {}’ dzięki czemu każdy element będzie automatycznie procesowany przez ten blok kodu za każdym razem po ‚wpadnięciu’ do potoku.
  • dzięki temu można usunąć ‚foreach’ bo blok ‚process’ i tak wykona się dla każdego elementu.

warto się sqpić nad konsekwencją tego faktu. tablice przekazywać na [co najmniej] dwa podstawowe sposoby – jako potok oraz jako parametr:

… ale po usunięciu ‚foreach’ ze skryptu, przestanie działać prawidłowo przekazanie przez zmienną wyliczaną…

aby przekonać się o tym, można uruchomić poniższy skrypt, na oba sposoby, różniący się od poprzedniego wpisu tylko weryfikacją czy element jest tablicą:

reasumując

dla zachowania możliwości wykonania zarówno poprzez potok jak i przez zmienną, lepiej zostawić pętlę foreach – nic złego nie robi.

eN.

foreach valuefrompipeline

*EDITED

mały tutorial o przetwarzaniu przekazywanych wartości, który może radykalnie zmienić czas przetwarzania skryptu. wiadomka – pipelining jest podstawowym mechanizmem PS a przy przetwarzaniu wielu elementów, czasem wręcz odruchowo, wpisuje się ‚%’ czyli foreach-object. przykładowo – znajdź wszystkich, którzy mają nazwisko na ‚x’ i wyślij im wiadomość:

a teraz standardowy scenariusz z życia codziennego: dostajemy jakieś listy w postaci pliqw tekstowych. załóżmy, że są w nim nazwy kont, z którymi coś trzeba zrobić. szkielet jest trywialny:

…mija czas i okazuje się, że nasze ‚do-something’ rozbudowaliśmy do postaci skryptu, ponieważ ilość wykonywanych czynności rośnie i oneliner jest zbyt mało wygodny. wartości można do skryptu przekazywać na dwa sposoby – bezpośrednio, jako parametr lub – tak jak powyżej – przez pipelining. druga metoda nie działa ‚od ręki’, wymaga włączenia poprzez specjalny parametr: ‚valueFromPipeline‚ [lub valueFromPipelineByPropertyName… ale to na inny wpis].

żeby pokazać co się będzie działo załóżmy, że mamy listę komputerów i operacja wymaga uwierzytelnienia się do zdalnego zasobu:

w takim przypadq, aby uruchomić skrypt dla całej listy, należy przekazać listę przez parametr:

polecenie w nawiasach ‚( )’ zostanie przetworzone, listing pliq zwraca tablicę stringów string[] i to zostanie przetworzone w skrypcie. jak na razie oczywiste oczywistości. nuda… ale zadanie nad którym pracujemy chcemy coraz bardziej automatyzować, cały proces do którego piszemy skrypty jest dość rozbudowany, a więc nasze skrypty muszą ze sobą gadać – output z jednego chcemy móc przekierować na kolejny. czyli trzeba włączyć pipelining:

jeśli przekażemy wartości przez parametr tak, jak do tej pory, to nic się nie zmieni. ale jeśli przekażemy przez pipe … coś nie halo:

..wyświetli tylko dla ostatniego elementu /: [zwróć uwagę, że skrypt ‚do-something’ wywołany jest bez parametru – valueFromPipeline oznacza ‚jeśli potok wyjściowy jest przekierowany, przekaż go do tej zmiennej oznaczonej valueFromPipeline’ ]

ah! no oczywiście! zapomnieliśmy foreach:

[tutaj już musi być parametr – $_ . a to dla tego, że nawiasy klamrowe ‚{ }’ definiują blok danych, separując potok od polecenia. niby niuans ale pokazuje, że totalnie zmienia się mechanika pod spodem]

hmm… no ale mamy kolejny problem – teraz skrypt przed każdym wywołaniem prosi o dane uwierzytelniające. lama poradzi sobie dodając parametr ‚credential’ i przekazując go podczas wywołania. ale to nie jest zawsze dobry sposób i dobrze wiedzieć czemu tak się dzieje. błąd został popełniony w momencie dodania ‚foreach’ (2). parametr ‚identities’ w skrypcie został sprytnie zadeklarowany jako tablica, a więc powinien tablicę przyjąć. ale dodając ‚foreach’, rozbijamy tablicę na poszczególne elementy i uruchamiamy skrypt wiele razy, przekazując każdą kolejną wartość jako parametr wywołania. a nie o to chodziło.

rozwiązaniem jest dodanie składni ‚begin-process-end’ do skryptu. standardowo skrypt czeka na pojedynczą wartość, po dodaniu tego bloq tworzy ‚pułapkę’ zawartą w bloq ‚process’, która będzie się uruchamiać dla każdego kolejnego elementu. co więcej, ‚process’ zostanie wykonany dla każdego przekazywanego elementu dokładnie tak, jak ‚foreach’, a więc można się pozbyć tego fragmentu:

teraz jeśli uruchomi się ‚do-sthelse | do-something’ – zostaniemy zapytanie o credsy tylko raz, po czym wykonana zostanie część ‚process’, a na koniec jednokrotnie wykona się klauzula ‚end’. wyrzucam ‚gwmi’ żeby pokazać przetwarzanie i zostawiam tylko write-host:

o to chodziło.

co zapamiętać

czym innym jest przekazanie tablicy a czym innym kolejne przekazywanie parametrów tablicy – czyli foreach. jeśli skrypt jest duży, to można dużo oszczędzić. dla tego przy pokaźnych operacjach warto zajrzeć do pomocy, opisu parametrów skryptu i sprawdzić czy deklaracja:

  • pozwala na przekazanie tablicy – np. [string[]]
  • pozwala na przekazanie przez pipe – valueFromPipeline

ponadto trzeba pamiętać, że ponieważ ‚valueFromPipeline’ jest pewnego rodzaju wskaźnikiem ‚TU PRZEKIERUJ WSZYSTKO CO WPADA’ – to może być zadeklarowane tylko raz. zadeklarowanie wielokrotnie nie spowoduje błędu składniowego, skrypt uruchomi się, ale wyniki będą mocno niedeterministyczne…

eN.

transformacja listy do csv

dane przekazywane są w różny, czasem dość dziwny sposób. ostatnio potrzebowałem danych do migracji w office365 i dane zostały przedstawione jako spis, gdzie jedynym wiążącym elementem była ilość wpisów dla każdego obiektu. coś takiego (example.txt):

takich wpisów było prawie 1oo a w efekcie chodziło o stworzenie tabeli, i dokonanie transpozycji:

nazwa parametr coś linia bez znacznika
jakaś nazwa wartość parametru tutaj jakaś wartość a tutaj kolejna wartość
inna nazwa inna wartość parametru coś i tu znów wartość
nazwa 3 parametr 3 tralalala blablabla
znów coś ciągle coś innego przykadowy ciąg znaków a tutaj kolejna wartość

 

jak widać zapis wygenerowany na stronie był dość luźny w stosunq do tego, co chciałbym mieć na końcu. tutaj poradziłem sobie przepisując ręcznie, ale przy dużej ilości wpisów…

wszystkiego nie ma sensu automatyzować, ale podstawowym zadaniem będzie owa transpozycja. w sumie to dwie linijki kodu:

pierwsza linijka to po prostu odczytanie zawartości pliq do zmiennej. a cała ‚transpozycja’ to de facto zauważenie, że:

  • każdy obiekt zapisany jest na 5 liniach
  • następnie jest pusta linia oddzielająca
  • kiedy sklei się wszystkie 5 linii średnikami.. to w zasadzie już

cały myk jak ładnie skleić wartości tabeli do stringa? wystarczy wskazać tabelę, i użyć ‚join’. ot – PowerShell. nie trzeba żadnych pętli ani wynalazków, wszystko zrobi za nas (; dodajmy do tego, że substrakt tabeli można uzyskać wskazując konkretne elementy, a jeśli są w zapisie ciągłym to wystarczy użyć ‚..’ . czyli tak:

inkrementując w pętli $i+=6 – to przeskakiwanie co 6 kolejnych linii.

‚podtabela’ma natomiast podane $i+5 aby ominąć ostatnią, pustą wartość.

…teraz wystarczy otworzyć w excelu i sobie resztę doklikać i uporządkować. voila.

eN.

 

Misja na Marsa

pół żartem, pół serio, przed chwilą pisałem, że moim marzeniem jest wziąć udział w projekcie interplanetarnym. a tu proszę – Misja na Marsa.

eN.

compare uncomparable

*UPDATED

bardzo często korzystam z ‚compare-object’ ale ma niestety jedną bardzo, bardzo poważną skazę. pomimo swojej nazwy, wcale nie potrafi porównywać obiektów, a raczej wykrywać różne obiekty w tablicy. oto przykład:

$t1 i $t2 są takimi samymi obiektami, różnią się niektórymi wartościami atrybutów – np. Paged Memory [PM(K)]. compare różnicy nie widzi. oczywiście można porównać konkretne atrybuty [properties]:

ale kiedy poda się kilka parametrów, to compare-object traktuje je jako logiczny OR –
„czy którykolwiek z nich się różni?”:

moje odczucie jest takie, że compare-object został napisany z myślą o tabelach, gdzie dla kolejnych wierszy pokazuje różnice w kolumnach. w przypadq obiektów jest odwrotnie – każdy wiersz jest unikalny i ma wartość. więc albo trzeba byłoby skonwertować to do tablicy i dokonać transpozycji, albo obejść się bez compare-object /: jak się okazuje nawet PowerShell ma wady i nie jest idealny. ten przypadek jest szczególnie bolesny i niezrozumiały, zarówno ze względu na obiektowość PS, jak i zwodniczą nazwę.

jeden ze scenariuszy: szukałem różnic w wartości obiektów po migracji między usługami, żeby wykryć, gdzie była zmiana. dla ułatwienia zrobiłem sobie zrzut obiektu do CSV [ale to nie ma znaczenia]. efekt był dokładnie taki jak opisywany powyżej, czyli nie pokazywał mi różnic. i trzeba było sobie to ręcznie oprogramować:

PS szybko rozleniwia /:

/UPDATE

okazuje się, że Tatuśkowi też zabrakło takiej funkcjonalności więc napisał piękną funkcję do jej obsługi: Compare-ObjectProperty.

dzięki Kacper za linka (:

eN.

 

 

 

unikaty i duplikaty

Duplikaty

łatwo jest przefiltrować listę tak, aby mieć tylko unikalne elementy – jest zarówno commandlet ‚get-unique’ oraz parametr ‚-unique’ przy select-object, ale jak wyłuskać duplikaty?

sposobów jest oczywiście wiele a ten, który mi się podoba to:

lub w hiperpoprawnym zapisie:

plik:

a teraz sprawdźmy duplikaty:

można jeszcze upiększyć output, pozbywając się śmieci:

Unikaty

powracając jeszcze do unikatów… wydawałoby się, że skoro jest oddzielne polecenie – get-unique, to powinno mieć większe możliwości i być bardziej elastyczne niż jakiś tam parametr do innego polecenia.

o dziwo jest odwrotnie. osobiście traktuję get-unique jako ciekawostkę i nie miałem scenariusza, w którym bym go użył. a to dla tego iż [msdn]:

The Get-Unique cmdlet compares each item in a sorted list to the next item, eliminates duplicates, and returns only one instance of each item. The list must be sorted for the cmdlet to work properly.

Get-Unique is case-sensitive. As a result, strings that differ only in character casing are considered to be unique.

eN.

conditional switch

Windows_PowerShell_iconczęsto zamiast budowy skomplikowanych IFów lepiej jest skorzystać ze switcha. czyli zamienić złożoną składnię bazowaną na wielu ‚if-then-else’ dużo czytelniejszym i prostszym blokiem ‚switch’. to oczywista oczywistość ale jest coś bardziej ‚zaawansowanego’ co jeszcze bardziej ułatwia życie – PowerShellowy Switch pozwala nie tylko na proste porównania, czy definicje wildcardów, które można znaleźć w manualu, ale również na tworzenie złożonych wyrażeń logicznych.

przykład takiego switcha:

test-switch.ps1

uwagę należy zwrócić na:

  • zastosowanie ‚break’ – standardowo switch wykona *wszystkie* bloki, spełniające warunek. w przypadku wywołania test-switch z parametrem 1 lub 2 pojawi się dodatkowo informacja ‚mniejsze niż 4 [ale nie większe niż 2]‚ . jeśli liczba będzie większa niż 3, wpadnie w klauzulę z ‚break’ i ostatni krok nie zostanie wykonany. dla tego należy pamiętać, że *kolejność ma znaczenie*.
  • dzięki temu, że switch wykonuje wszystkie bloki spełniające warunek, można zrobić krok typu ‚catch all’ – który wykona się zawsze. ale warto umieścić go jako pierwszy tak, żeby nie przerwał go jakiś break. najlepiej użyć ‚switch -wildcard’ -> manual.
  • w instrukcji [man switch] można znaleźć bardzo fajne przykłady dla wyrażeń regularnych i wildcardów, dla tego pomijam go w tym prostym przykładzie. ale warto wiedzieć, że można wykonywać również zaawansowane porównania na ciągach znaków.
  • to czego zabrakło w manualu to właśnie przykład wyrażenia logicznego. klauzulą może być dowolne wyrażenie zamknięte w nawiasach klamrowych {} . oczywiście dla determinizmu zachowania powinno zwracać true/false.
  • PS switch nie pozwala na definiowane tego samego bloku dla kilq wartości [listy] tak, jak to się robi np. w VBS, czyli nie da się zdefiniować ‚ 1,2 { blok } ‚ . w zamian można użyć warunku logicznego ‚{1 -or 2} {blok} ‚ . trochę mniej wygodne, ale działa tak samo (:

proste i wydajne. proponuję dla gimnastyki rozpisać to sobie na IFach… (;

eN.

 

szkolenie PowerShell – jak pisać skrypty

MVAw końcu! materiał na długo utknął w postprodukcji (; ale w końcu jest – 3cia część szkolenia, tym razem już dla mniej-początqjących – ‚jak pisać skrypty/funkcje’. szkolenie jest na pewno ciekawsze, ponieważ towarzyszy mi Darek Porowski, który pilnuje żebym nie przynudzał za bardzo. i to [chyba] zadziałało q:

zachęcam do zapoznanie się z materiałem i oceny ::))o- PowerShell dla zaawansowanych – http://aka.ms/plmva-psadv

eN.

Powershell on Linux

devopskilka dni temu został oficjalnie zaprezentowany PowerShell dla Linux. co prawda na razie w wersji Alpha, niemniej jest to wielka sprawa. .Net był zapowiadany jako wielo-platformowa alternatywa dla Javy podczas, kiedy wychodziła wersja 1. trzeba było czekać dekadę – od 2o14 MS wspiera rozwój projektu Mono, dzięki czemu w końcu powstała wersja .NET, pozwalająca na przeniesienie PSh na Antarktydę (;

Linux w kilq miejscach utknął w latach 9o’ i tak jest m.in. z konsolą i ‚string-thinking’ czyli operowaniem na ciągach. kto popracował z obiektami i poznał realną przyjemność pracy z ich obróbką [filtry, export/import, badanie parametrów itd], ten wie o czym mowa. to oczywiście jeden z ważniejszych aspektów, ale najważniejszy, który wpisuje się w promowany trend DevOps i Cloud, to ujednolicenie środowisk. 1/3 wszystkich maszyn działających w Azure to Linuxy, co pokazuje zarówno do czego tak na prawdę jest ‚Chmura’ oraz jak światy MS/Lin zaczynają się przenikać. a to oznacza, że developerzy, tudzież DevOpsi, potrzebują jednolitych środowisk, bez względu na platformę. to warstwa, która przez lata dzieliła światy i w końcu staje się tylko kolejną warstwą abstrakcji – czy pracuje się na Windows czy na Linux, można to robić w coraz bardziej zunifikowany sposób.

ci, którzy nie wierzą, i jeszcze się z tym nie spotkali, niech obejrzą prezentację: https://channel9.msdn.com/Blogs/hybrid-it-management/PowerShell-on-Linux-and-Open-Source

podczas oglądania warto zwrócić uwagę na to, jak coraz trudniej odróżnić na którym systemie ktoś pracuje – np. Visual Studio Code działające na Linux i na Mac, PSh na Mac, Linux czy VMWare, jednolity sposób zarządzania środowiskami …

pamiętam czasy, kiedy wystarczyło rzucić nieopatrzne hasło nie na tym forum i z wpisów tryskała krew nienawiści i słowne krucjaty w wojnie o to, który system jest najlepszy i jak bardzo moja mojszość jest mojsiejsza. przyjemnie patrzeć jak z tego średniowiecza przechodzimy do prawdziwego renesansu, wymiany myśli i współpracy między platformami, z korzyścią dla całego rynq. hasło ‚DevOps’ wprowadza nas do nowej epoki na rynq IT będąc taką samą rewolucją w myśleniu, jak jakiś czas temu wirtualizacja.

eN.

 

logowanie na szybko – commandlet defaults

Windows_PowerShell_icondobrze jest dodawać jakieś logi do skryptu. można sobie ułatwić to zadanie na wiele sposobów, ale chciałem dorzucić jeszcze jeden, który może przydać się przy innych scenariuszach, jeśli tylko często wykonuje się jakieś polecenie z takimi samymi wartościami parametrów.

jeśli logowanie robimy przekierowując przy pomocy out-file to co chwila będziemy wpisywać:

niby nie dużo, ale czemu nie skrócić tego zapisu? można ustawić standardowe wartości parametrów dla wszystkich commandletów. robi się przy pomocy zmiennej $PSDefaultParameterValues, a w praktyce wygląda to np. tak:

eN.