Pokieruj swoim skryptem – poznaj workflows!

Jak to w świecie IT bywa – pewne zagadnienia wymagają pewnych rozwiązań. Kiedy czasem (zawsze) chcesz obsłużyć błąd, korzystasz ze struktury try-catch, kiedy potrzebujesz coś zaprogramować, wybierasz (albo powinieneś wybrać) język programowania, który pozwoli Ci to osiągnąć w najkrótszym czasie/najwydajniej (zależnie od wymagań), kiedy potrzebujesz bazy danych to…

Nie ma większego od Excela!

Excel spełnia wymagania wielu i choć każdy techniczny wie, że nie służy do przechowywania danych, to jest on w znacznym stopniu do tego wykorzystywany, bo porządkuje w sposób logiczny i czytelny dla użytkownika dane. Workflows porządkują Twój skrypt w PowerShellu.

Formalnie, workflows w PowerShellu uruchamiany jest przez Windows Workflow Foundation – mamy więc do czynienia z pewnym narzutem, gdyż składnia PowerShella ostatecznie jest i tak tłumaczona do postaci rozumianej przez Windows Workflow Foundation. Po co sobie zawracać nimi głowę?

Jeśli Twoje repozytorium to tylko onelinery – workflows nie są dla Ciebie.

Kiedy Twoje skrypty są bardzo nieuporządkowane, nieczytelne i ciężko się w nich odnaleźć – być może workflows są dla Ciebie.

Jeśli piszesz zaawansowane skrypty, ale wciąż nie poznałeś workflows – to myślę, że są one dla Ciebie.

Sztandarowymi przypadkami użycia workflows są:

  • Aktywności, które mają być uruchamiane równolegle,
  • Bardzo długo działające skrypty,
  • Często używane zadania,
  • Możliwość wznawiania skryptu po awarii poprzez definiowanie checkpointów

Składnia ta pozwala na ułożenie skryptu w sposób logiczny, sekwencyjny i ułożony, a co ciekawe – pozwala na wdrożenie równoległości. Tak, możesz na przykład spingować 100 maszyn w pętli foreach i czekać znacznie krócej, niż zrobiłbyś to w sposób tradycyjny. Przetestuj działanie poniższych poleceń u siebie:

U mnie różnica dla kilku hostów jest już dość znaczna, a przynajmniej tak odbieram blisko 9 razy szybciej wykonany program.

Ok 4.5 sekundy vs ok. 0.5 sekundy

Podstawowe użycie powinno zawierać słowo kluczowe „workflow”, jego nazwę (tak jak nazywa się funkcje) i nawias klamrowy.

workflow Nazwa-Powershellowa {
    <Komendy tutaj>
}

Powyżej zastosowałem wewnątrz przepływu dyrektywę pozwalająca na wykonanie komend równolegle (foreach -parallel), jednak o parareliźmie możemy informować podając słowo kluczowe „parallel” i otwierając nawias klamrowy. Gdy sytuacja tego wymaga, możemy wyraźnie zaznaczyć bloki, które muszą wykonać się jeden po drugim – np. restartując różne serwisy na różnych serwerach (albo te same serwisy na różnych serwerach) pilnujemy, aby wykonały się w odpowiedniej kolejności. Sekwencyjność zapewnia blok „sequence”. Przykład:

workflow Test-Workflow {
   Parallel{
       <#1 Ta komenda wykona się jednocześnie na wielu celach>
       <#2 Ta również, w tym samym czasie>
       Sequence{
           <#3 Ta również w tym samym czasie co #1 i #2>
           <#4 Dopiero jak #3 skończy działanie>
           <#5 Dopiero jak #4 skończy działanie>
       }
   }
}

Jak widać powyżej, należy być szczególnie uważnym projektując przepływ jak powyżej. Komendy 1-3 wykonają się jednocześnie, sekwencja jest częścią bloku równoległego, więc pierwsze działanie w sekwencji wygląda jak kolejna pozycja w bloku równoległym, dopiero później kolejność w bloku sekwencji ma znaczenie.

Workflow możemy więc wykorzystać do szybkiego zbierania danych z serwerów i wykorzystywanie ich dalej w znacznie krótszym czasie niż dotychczas. Ponadto, workflow jest w stanie przeżyć restart serwera – może więc posłużyć do konfiguracji serwera wymagających wiele restartów między kolejnymi etapami. Wystarczy podążać za tzw. checkpointami. Brzmi super prawda?

Wszystko będzie dobrze, o ile nasze skrypty zostaną faktycznie zmodyfikowane i będą trzymać się poniższych zasad:

Nie wszystkie komendy działają w workflow

Przede wszystkim komendy, które mogą współdzielić dane (czyli dodawanie elementów do listy), formatują je lub w jakiś sposób przetwarzają. Mądrzejszy ode mnie Dr Scripto utworzył już tabelę jakich cmdletów używać nie można w workflow, jakie techniki nie zadziałają:

Jakich technik używać nie można. Źródło: https://devblogs.microsoft.com/scripting/powershell-workflows-restrictions/
Niektóre cmdlety też nie zadziałają. Źródło: https://devblogs.microsoft.com/scripting/powershell-workflows-restrictions/

Biorąc pod uwagę powyższe – debugowanie takiego skryptu może być nieco karkołomne i jeśli mają to być testy na produkcji – trzeba być wyjątkowo ostrożnym tj. używać WhatIf tam gdzie się da. Można ich jednak użyć w specjalnej składni InlineScript, którą opiszę w dalszej części artykułu.

Obiekty są zdeserializowane

Aktywności w workflow są konwertowane do XAML i zwracają serializowaną reprezentację obiektów.

Co to w praktyce oznacza? Wynik działania komendy w workflow potraktuj dokładnie tak samo jak wynik zdalnego wykonania. Masz dostęp do właściwości obiektu, ale już nie do jego metod. I to dotyczy również tych lokalnych komend, jak Get-WmiObject. I ponownie – jeśli chcesz możesz ich użyć w bloku InlineScript.

Zasięg zmiennej jest zupełnie inny niż zdążyłeś się przyzwyczaić

Generalnie zasada jest taka, że zmienne globalne są dostępne wszędzie o ile nie są przesłonięte przez zmienne lokalne – to dość uniwersalna zasada i dotyczy wielu języków programowania. Workflow zaprzecza drugiej części – zmienne lokalne nie mogą mieć takich samych nazw jak zmienne globalne. A tak w zasadzie – nie ma globalnych zmiennych, a więc zmienna $global nie zadziała. Mamy po prostu większe lub mniejsze zakresy. Jeśli chcemy „dobrać się” do zmiennej workflow z InlineScript, musimy użyć $Using:nazwazmiennej. Do odczytu zawartości zmiennej wyższego poziomu wystarczy podać nazwę zmiennej, ale jej modyfikacja powinna nastąpić poprzez użycie $workflow:nazwazmiennej. Poniżej postaram się wyjaśnić poziomy:

workflow test{
    # to jest zmienna najwyższego poziomu - jest ona dostępna w każdym innym poziomie
    $a=3
    parallel {
        #tutaj mamy poziom niżej, możemy odczytać zmienną jak tutaj
        "Wartość zmiennej a: $a"
        # modyfikacja zmiennej
        $workflow:a=18
        "Wartość zmiennej a po modyfikacji: $a"
        #dodajemy zmienna na poziomie pierwszym
        $b = 5
        sequence{
            # odczytujemy $a na poziomie niżej
            "Wartość zmiennej a na jeszcze niższym poziomie: $a"
            # a teraz $b
            "Wartość zmiennej b na jeszcze niższym poziomie: $b"
            $workflow:b = 3 #oops! tutaj otrzymamy błąd - nie możemy modyfikować zmiennych innych niż na poziomie najwyzszym!
        }
    }
    InlineScript{"Wartość zmiennej w sesji PowerShell a: $a"}
    InlineScript{"Wartość zmiennej w sesji PowerShell a uzywając Using: $Using:a"}


    "Wartość zmiennej workflow a: $workflow:a"
}

Linia 11 okaże się pusta – ponieważ InlineScript nieco inaczej obsługuje to, co workflow. Jak widać, wszędzie propagowane są zmienne na najwyższym poziomie, które można modyfikować. Zmienne z innego poziomu są również możliwe do odczytania, ale ich modyfikacja jest już niemożliwa.

Jeśli komenda nie ma swojego odpowiednika workflow – po prostu jej nie użyjesz

Chyba, że użyjesz jej w bloku InlineScript.

Czym jest InlineScript?

Powiedzieliśmy sobie na początku, że workflow to Windows Workflow Foundation (WWF), więc nie możemy tutaj mówić, że jest to dokładnie ten sam PowerShell który znasz. W WWF każda komenda jest uruchamiana w swojej własnej sesji i własnej przestrzeni nazw. Być może teraz już rozumiesz, dlaczego w tym koncepcie udostępnianie danych między kolejnymi krokami jest nieco bardziej skomplikowane niż w standardowym skrypcie. InlineScript to taki przełącznik w workflow który mówi „hej, potrzebuje teraz naprawdę PowerShella i działać na pełnych obiektach!”. W ten sposób, chociaż sama struktura workflow bo wgłębieniu się w nią wydaje się skomplikowana, zyskujemy nieco elastyczności. InlineScript nie pozbawia nas korzyści wynikających z wielowątkowości – po prostu przenosi nas do sesji poczciwego PowerShella.

Czy warto stosować workflow?

Moim zdaniem zdecydowanie tak. Zwłaszcza, jeśli nie posiadasz narzędzi do automatyzacji, a Twoje środowisko jest większe niż kilka komputerów/serwerów. Jeśli jeszcze nie korzystałeś z tej techniki – gorąco zachęcam Cię do napisania lub przerobienia jednego ze swoich skryptów.

Jeśli czujesz, że artykuł nie wyczerpuje w pewnym zakresie zagadnienia – napisz o tym w komentarzu!

Marcin Kuchczyński

Wielki fan automatyzowania wszystkiego, co trzeba wykonać więcej niż 2 razy. Cierpliwie rozwijający się w kierunku rozwiązań chmurowych i raczkujący w sferze sztucznej inteligencji. W IT od 2016 roku.

1 Odpowiedź

  1. Wardriving pisze:

    Dzięki za wpis na pewno się przyda.

Leave a Reply