jak usunąć ostatni element z tablicy?
$array=$array[0..($array.count-2)]
jest ’-2′ a nie ’-1′ bo liczymy od zera.
eN.
$array=$array[0..($array.count-2)]
jest ’-2′ a nie ’-1′ bo liczymy od zera.
eN.
uruchamiając skrypt, najbezpieczniej jest NIE hardcodować hasła. jeśli coś jest w skrypcie, to znaczy, że może być wykorzystane w nieautoryzowany sposób. jednak przykłady z życia pokazują, że czasem taka jest konieczność .. czy po prostu zlecenie (; przykład – obsługa wsparcia, która ma korzystać ze skryptu, który gdzieś tam sobie sięga. to 'gdzieś tam’ to środowisko, w którym nawet owa obsługa nie ma konta.
podstawowe zasady bezpieczeństwa to 3xA (AAA) – Authentication, Authorization & Accounting. jeśli utworzymy konto serwisowe, które ma coś wykonywać w imieniu uruchamiającego, to aby nie złamać zasady AAA i być w stanie stwierdzić kto wykonał daną akcję, trzeba to przesunąć do miejsca, gdzie uruchamia się skrypt/aplikację i umieć to powiązać… dalej mogłoby być o SIEM i tak dalej… ale nie o tym tutaj. ogólnie najważniejsze – wykorzystanie konta serwisowego (w środowisq legacy-domain), czy aplikacji proxy (tak jak działa to w Azure) nie musi koniecznie być złem, ale pozostaje pytanie… *jak zamieścić hasło skrypcie tak, aby nie wyciekło wraz ze skryptem?*
najbezpieczniej byłoby wykorzystać certyfikat… tak to można zrobić np. dla aplikacji Azure. niestety w środowisq klasycznym, gdzie mamy np. wykonać akcję w domenie, nie jest to łatwe. najbezpieczniej byłoby umieszczenie serwisu aka proxy, który działa sobie na serwerze w owej domenie i do tegoż serwisu uwierzytelniać się certyfikatem. spoko ale to developerka i do 'małych projekcików’ czy 'drobnych narzędzi’ – po prostu jest za duża czasochłonność (czyt. koszt), nie wspominając o tym że napisanie własnego serwisu (np. wystawiającego REST API) to nie jest już skryptowanie. to developerka.
no więc zróbmy to, co da się zrobić tak, aby było szybko i *możliwie* bezpiecznie.
skoro nie jesteśmy w stanie uwierzytelnić się certyfikatem, to przynajmniej zaszyfrujmy hasło certyfikatem. co nam to da:
żeby była jasność – jeśli ktoś, kto ma złe intencje będzie tego skryptu używał, to sobie hasło odkoduje. ale po pierwsze – 'pierwszy lepszy’ tego nie zrobi, po drugie – jeśli założylibyśmy takiej osobie konto, to i tak wykorzysta je do niecnych celów. trzeba wiedzieć że to może być rozwiązanie *good enough* i tylko w tym kontekście można nazwać je 'bezpiecznym’. spory disclaimer ale nie chcę przypadkowych czytelników wprowadzić w błąd.
jak już wyjaśniłem co rozumiem przez 'bezpieczne’, recepta:
punkty 1-3 pominę, natomiast 4-6 zaraz opiszę.
dzięki takiej konfiguracji – skrypt, nawet skopiowany czy przypadkowo udostępniony, na niewiele się zda. aby wydobyć hasło – trzeba mieć dostęp do klucza prywatnego certyfikatu.
super proste, przy czym do tego celu cert musi spełniać odpowiednie funkcje, czyli (nomen-omen) kluczem jest dobry key-usage i document type:
$cert=New-SelfSignedCertificate -DnsName "script automation" -CertStoreLocation "Cert:\CurrentUser\My" -KeyUsage KeyEncipherment,DataEncipherment,KeyAgreement -Type DocumentEncryptionCert $cert|Export-PfxCertificate -FilePath C:\temp\scriptautomation.pfx -Password (ConvertTo-SecureString -String "secret-string" -Force -AsPlainText)
dodatkowo można certyfikat usunąć z własnego komputera tak, aby jedna kopia była w pliq:
$cert|remove-Item
…albo zachować go jako backup a usunąć potem plik. up2u.
najłatwiej oczywiście kliknąć sobie na pliq pfx i wybrać opcję 'local machine’. jeśli umieścimy w 'current user’ to będzie dostępny tylko dla nas.
kolejną hiper-istotną kwestią jest *NIE włączanie* możliwości exportu klucza.
jeśli ktoś woli z PowerShell – należy użyć ’import-pfxCertificate’ *bez* parametru -exportable.
Import-PfxCertificate -FilePath C:\temp\scriptautomation.pfx -Password (ConvertTo-SecureString -string "secret-string" -force -AsPlainText) -CertStoreLocation Cert:\LocalMachine\My\
ciekawostka: w PS 5.1 ten commandlet ma dodatkowy parametr, nieopisany w doc, protectPrivateKey, który pozwala wykorzystać Virtual Secure Mode.
to połowa sukcesu – bo do tak zaimportowanego certyfikatu, nikt bez uprawnień administratora nie będzie mógł skorzystać. należy nadać uprawnienia do klucza prywatnego:
4. nadaj uprawnienie READ (nie FC!) dla wybranych osób
teraz już z górki. przygotowanie środowiska to bardziej wymagający element, ponieważ hasło można zaszyfrować za pomocą polecenia ’protect-cmsMessage’:
C:\_scriptz :))o- Protect-CmsMessage -To 'cn=script automation' -Content 'moje tajne hasło' -----BEGIN CMS----- MIIBtAYJKoZIhvcNAQcDoIIBpTCCAaECAQAxggFMMIIBSAIBADAwMBwxGjAYBgNVBAMMEXNjcmlw dCBhdXRvbWF0aW9uAhB2BdZafxn2nkcWjQNvBi+pMA0GCSqGSIb3DQEBBzAABIIBAFY0TU8LAPl4 4IAWp9tGDOZK/bAEwQpZPix5dz8AoOpaDckpZ8dqatggEKq7vo4VX6wL4sBkImQoZrCZjkT7oCSi N1YFDOIghjD7e2mIvEl/Gq2bReUbsFQ0iw6Wg1K8zVLBzDQAIUHgJvaV2Ssf4nCJ8WfW5d9UzmBB JpHAmy7cdofboQt6hRz0wafGNivD47z2xNSSVyhqHVUzBt6NWmAYouFMGYGsBZBuOHXnQJzh+saG Q5VpWxZGRHzM3igl8IgYDF75R+b/FSfciPu5Se2eeD6xxHrPj9rfLm37KVIab/4+QA/lRFVt4cwA ztjhh8puyPqYgKCE7t0Tp5VNQv4wTAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQjmYztOm64boC 6XqnH/9kMYAgYTQlOXeGex7qMH5S5gVRKy/JOhfIdqlabP9e/N/6iRk= -----END CMS-----
ciekawostka: przy tym mechaniźmie szyfrowania (Cryptographic Message Syntax), uruchomienie tego polecenia, da za każdym razem inny wynik
jeśli ktoś nie pamięta nazwy certu, to można je szybko wylistować:
C:\_scriptz :))o- ls Cert:\LocalMachine\My\ PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\My Thumbprint Subject ---------- ------- B643393E34BDC10BE2266F307F63A712578416F1 CN=script automation
wkleić sobie ten ciąg do skryptu i kiedy potrzebne jest hasło, użyć unprotect-CMSMessage… np. tak:
[string]$encPass="-----BEGIN CMS----- MIIBtAYJKoZIhvcNAQcDoIIBpTCCAaECAQAxggFMMIIBSAIBADAwMBwxGjAYBgNVBAMMEXNjcmlw dCBhdXRvbWF0aW9uAhB2BdZafxn2nkcWjQNvBi+pMA0GCSqGSIb3DQEBBzAABIIBAFY0TU8LAPl4 4IAWp9tGDOZK/bAEwQpZPix5dz8AoOpaDckpZ8dqatggEKq7vo4VX6wL4sBkImQoZrCZjkT7oCSi N1YFDOIghjD7e2mIvEl/Gq2bReUbsFQ0iw6Wg1K8zVLBzDQAIUHgJvaV2Ssf4nCJ8WfW5d9UzmBB JpHAmy7cdofboQt6hRz0wafGNivD47z2xNSSVyhqHVUzBt6NWmAYouFMGYGsBZBuOHXnQJzh+saG Q5VpWxZGRHzM3igl8IgYDF75R+b/FSfciPu5Se2eeD6xxHrPj9rfLm37KVIab/4+QA/lRFVt4cwA ztjhh8puyPqYgKCE7t0Tp5VNQv4wTAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQjmYztOm64boC 6XqnH/9kMYAgYTQlOXeGex7qMH5S5gVRKy/JOhfIdqlabP9e/N/6iRk= -----END CMS-----" try { $cert = Get-ChildItem Cert:\LocalMachine\My\B643393E34BDC10BE2266F307F63A712578416F1 -ErrorAction stop } catch { write-log "missing authentication certificate. quitting" -type error retrun $null } if(-not $cert.HasPrivateKey) { write-log "missing decription factor. quitting." -type error return $null } $certCN = $cert.Subject try { [securestring]$secStringPassword = ConvertTo-SecureString (Unprotect-CmsMessage -Content $encPass -To $certCN -ErrorAction stop) -AsPlainText -Force } catch { write-log "error decrypting auth password $($_.exception)" -type error return $null } [pscredential]$creds = New-Object System.Management.Automation.PSCredential ('CORP\SVC-contactCreator', $secStringPassword)
jakiś czas temu linkowałem dostęp do EXO certyfikatem. wygodne.
a podczas uruchamiania własnych skryptów, i tam gdzie wystarczą zwykłe credsy, nie chce mi się wpisywać hasła. zapisuję więc je sobie do pliq:
if(test-path $credsFile) { $myCreds = Import-CliXml -Path $credsFile write-log "used saved credentials in $credsFile" -type info } else { $myCreds=Get-Credential if($NULL -eq $myCreds) { write-log 'Cancelled.' -type error exit -3 } if($saveCredentials) { $myCreds | Export-Clixml -Path $credsFile write-log "credentials saved as $credsFile" -type info } }
get-Credential używa DPAPI i w 'zamkniętym’ środowisq (np. na własnym lapq) w zupełności wystarcza. z tego co kojarzę szyfrowane jest kluczem użytkownika i komputera więc taki plik, aby był odczytany, musi być w tym samym środowisq. mimo wszystko w 'otwartym’ środowisq raczej nie należy stosować takich metod.
eN.
taka zabawka… skrypt destroy-AzureVM do usuwania VM wraz z zasobami powiązanymi:
przydatne zwłaszcza do LABów, żeby nie zapominać i nie płacić bez sensu za przypadkowo pozostawione śmieci.
eN.
przeglądając ostatnio changelog dla commandletów ExchangeOnlineManagement znalazłem bardzo miłą informację.
po pierwsze w końcu PS dla EXO zaczyna się normalizować. po dziwnych zawirowaniach i wydania ExchangeOnline 1.0.1 określonej jako… V2, w końcu ktoś poszedł po rozum do głowy i dał i wersję 2.x . niby drobna rzecz, ale istotna, ze względu na przejrzystość.
ponadto, pomimo że GraphAPI dla EXO jeszcze nie ma, dostarczony został [trochę wydrutowany, ale zawsze] sposób, na bezhasłowe połączenie do konsoli. nie wymaga to zbyt dużo gimnastyki, a pozwala na tworzenie skryptów w trybie nienadzrorowanym [unattended].
eN.
zadanie jest proste – napisać GUI, które pozwoli wyłączyć maszynę w Azure z opcją force. tego normalnie z interfejsu zrobić się nie da, a operacja potrzebna. chodzi o przeniesienie zadania z 2giej czy 3ciej linii wsparcia do 1szej, czyli nie ma opcji na jakąkolwiek linię poleceń. musi być GUI.
poniżej dwa skrypty, które realizują to samo zadanie. jeden napisany w tym co PS daje [z małym wyjątkiem], drugi w Formsach. przykład ma posłużyć do porównania tych metod i pozwolić się zastanowić jakie są 'za’ i 'przeciw’ dla obu.
pełny skrypt można pobrać z GitHuba, poniżej omówienie fragmentów.
założeniem tej wersji jest szybkość działania i uniwersalność. nie korzystam póki co z wersji PS Core ale na pewno korzystanie z biblioteki forms nie będzie możliwe. dla Core można korzystać z XAML UI, którego również jeszcze nie testowałem. jak już pisałem – jedną z bolączek pisania skryptów z GUI jest już sam dobór bibliotek i decyzja 'gdzie ten skrypt będzie uruchamiany i przez kogo’ /:
dla tego 'natywne’ skrypty zachowują lepszą kompatybilność i uniwersalność.
niestety natywnych kontrolek jest niezmiernie mało. najważniejszą jest out-GridView, które umożliwia wyświetlenie listy lub obiektów w postaci interaktywnej tabeli, pozwalając na sortowanie, filtrowanie etc. pozwala również na wybranie pojedynczego lub wielu elementów – czyli może być przydatny również wtedy, kiedy chcemy pozwolić użytkownikowi wybrać obiektów do dalszego przetworzenia. i choć daje wiele możliwości, to równocześnie bardzo niewielką kontrolę.
fragment kodu do którego się odwołuję to:
function select-RG { param( $RGList ) write-host -ForegroundColor Yellow "Select Resource Group VM resides on" $RG=$RGList|out-gridview -title 'Select Resource Group' -OutputMode Single if([string]::isNullOrEmpty($RG)) { write-host 'cancelled by user. quitting' -foreground Yellow exit -1 } write-host "$($RG.ResourceGroupName) chosen. reading VMs..." return $RG.ResourceGroupName }
w szczególności linia pokazująca listę odczytanych Resource Groups w postaci interaktywnej. Out-GridView 'daje-to-co-daje’ czyli nie da się kontrolować wyglądu okna. to co możemy zrobić to:
siła tkwi w prostocie. chwilę później jednak można zobaczyć:
do { #choose RG $ResourceGroupName=select-RG -RGList $RGsInThisSub $VMlist=get-VMList -RGname $ResourceGroupName if([string]::isNullOrEmpty($VMlist)) { write-host "This Resource Group do not contain any VMs. Do you want to select another RG?" switch ( [System.Windows.Forms.MessageBox]::show($this,"Choose another Resource Group?",'CONFIRM','OKCancel') ) { 'OK' { #do nothing - VMList is null which will trigger loop } 'Cancel' { Write-Host -ForegroundColor Yellow "operation cancelled by the user. quitting." exit -1 } } } } while( [string]::isNullOrEmpty($VMlist) )
czemu nagle pojawia się Forms? to niestety sqcha twórców PowerShell – o ile WScript dysponował prostym okienkiem OK/Cancel, o ile jest OGV w PS… o tyle nie ma takiego prostego okienka OK/Cancel w PS.
co ciekawe, można takie okienko wyświetlić bez Forms! w taki sposób:
Add-Type -AssemblyName PresentationFramework [System.Windows.MessageBox]::show("Choose another Resource Group?",'CONFIRM','OKCancel')
pomimo, że wyglądają bardzo podobnie, i dają niemal ten sam efekt, pod spodem wydarzają się trochę inne rzeczy. jeden jest częścią PresentationFramework drugi Forms, mają inne konstruktory. lepiej używać Formsowego z dwóch powodów:
jak już coś pisaliście co wymaga interakcji, powinniście zadać pytanie – czemu nie użyć readKey? natywne, nie wymaga importu bibliotek, szybsze … i tak dalej.
zgoda. ale celem nadrzędnym jest wygoda endusera i założenie, że nie jest bystrym inżynierem (; kiedy zrobiłem readKey, a skrypt miał mieć GUI, sam łapałem się na tym, że czekałem i czekałem… aż zorientowałem się, że to skrypt czeka na mnie, a nie odwrotnie. załamanie logiki – tutaj interfejs a tu linia poleceń – jest bardzo złym podejściem. albo decydujemy się robić skrypt tak, albo inaczej – ale musi być spójnie. inaczej ani nie jest łatwy w użyciu ani prosty w strukturze.
readKey to nie GUI tylko metoda na interakcję bez GUI.
całość do pobrania z GitHub . kilka uwag n00ba dotyczących pisania PS+Forms.
pierwszą rzeczą jaka rzuca się oczy to narzut ilości kodu. do wykonania mamy jedno polecenie (jedna linijka). w wersji opisywanej wcześniej wyszło 126 linii kodu, tutaj mamy już prawie 19o. jasne się staje że podstawowym problemem będzie możliwy bałagan wynikający z samej ilości. dla tego części dotyczące rysowania samego interfejsu warto oddzielić od reszty. niektórzy decydują się na utworzenie projektu, w ramach którego jest kilka oddzielnych pliqw, i definicje interfejsu wyrzuca się do takiego oddzielnego pliq. spoko, ale ze względu na spójność, przy takich małych toolach wolę trzymać wszystko w pojedynczym pliq. łatwiej go przesłać do niedoświadczonych użytkowników, wytłumaczyć że to taki plik i już, niż kazać tworzyć jakąś strukturę, czy martwić się, że ktoś kawałek usunął czy nie skopiował. ale to oczywiście kwestia wyboru – ważne, żeby sobie oczyścić kod i możliwie mocno oddzielić logikę od definicji.
nie jest to oczywiście do końca możliwe, bo tak, jak opisywałem poprzednio, logika jest de facto związana z interfejsem – trigger-action. klikniemy guzik to uruchomi się jakiś kawałek. całą sekwencyjność szlag trafia.
ja póki co przyjąłem metodę tworzenia regionów – widać znaczniki #region i #endregion które dzielą skrypt na bloki – tutaj 3 bloki – interfejs, akcje interfejsu i cała reszta. zaleta jest taka, że większość edytorów rozpoznaje ten znacznik i pozwala zwinąć tą część kodu żeby nie pasqdziła widoq.
niewątpliwie pisanie skryptów z GUI jest dużo trudniejsze i dużo bardziej czasochłonne. tak, jak przy zwykłym skrypcie 6o-8o% czasu to praca nad logiką działania, tak tutaj, ok. 9o% czasu zjadło mi badanie reguł interakcji między poszczególnymi elementami. ok, uczę się więc potem będzie łatwiej, ale nawet przy tak banalnym skrypciq sprawdzenie czy odpowiednio wyczyszczą się wartości konkretnych kontrolek, czy finalnie ustawiona/przeczytana zmienna jest prawidłowa, czy może pozostało coś z klikania usera, czy guziki są aktywne kiedy trzeba, do tego jak to zoptymalizować, że nie ładowało w kółko po pół minuty…
do tego commandlety Az są… hmm.. nie działają zbyt dobrze q: connect-AzAccount się regularnie [niedeterministycznie] zawiesza po zabiciu okna logowania [cancel], zawiesza się dużo bardziej w Vistual Studio Code, a get-AzContex nie implementuje prawidłowo ErrorAction SilentlyContinue…. żeby tak podać najważniejsze. ogólnie to dość trudna biblioteka do współpracy, bez względu na GUI.
eN.
już za tydzień ITechDay. zastanawiałem się, jak to będzie wyglądało organizacyjnie, a ponieważ jestem po spotkaniu z organizatorem, garść informacji. jeśli jesteś zarejestrowanym uczestnikiem to pewnie już dostałeś instrukcje, ale IMHO najważniejsze:
w dobie 'wszystko zdalnie’ uczestniczyłem już w różnych eksperymentach – ten niewątpliwie będzie największym/najbardziej rozbudowanym. jedną z najcenniejszych funkcji konferencji jest networking, i ta formuła ma go umożliwić. podobnie do realnego wydarzenia będą 'stoiska partnerów’ czyli oddzielne breakout rooms gdzie można będzie zapoznać się ofertami sponsorów i dowiedzieć czegoś na temat ich produktów, hydepark aka „wirtualna pizza” – miejsce, gdzie będzie można swobodnie sobie chatować z innymi i kilka innych ciekawych pomysłów.
…reszta już w rękach uczestników.
PS. a w tym tygodniu virtualny Ignite. tak dla porównania q:
eN.
już 29.IX, [przekornie] ostatni wtorek miesiąca, odbędzie się konferencja ITechDay. również będę miał zaszczyt poprowadzić jedną z sesji. niestety, nadal w atmosferze covidowym, czyli zdalnie, w postaci Teams Live Events, ale co najważniejsze – live. modne ostatnio robi się ogłaszanie 'konferencji’, które okazują się spreparowanym portalem z sesjami offline…. nie tutaj (:
…bardzo nie lubię sesji zdalnych, brak kontaktu z publiką nie daje feedbacku… ale cóż. znak czasów. mam nadzieję, że ITD21′ odbędzie się już w pełni na żywo. jest opcja komentowania, co prawda z opóźnieniem ~3osec, ale zawsze. przynajmniej nie ma problemu z wejściówkami (;
eN.
Społeczność WGUiSW.org wraz z Partnerami gorąco zapraszają na kolejną konferencję z cyklu ITechDay.
Wydarzenie odbędzie się w formule online z wykorzystaniem platformy Microsoft Teams.
Tematami wiodącymi konferencji będą:
Sesje będą odbywały się równolegle w sześciu ścieżkach tematycznych:
Sesje poprowadzą znani prelegenci posiadający bardzo bogate doświadczenie praktyczne poparte wieloma certyfikatami zawodowym.
Udział w konferencji ITechDay jest bezpłatny.
Zapraszamy na www.ITechDay.pl oraz www.facebook.com/ITechDay.
install-module eNLib
install-module eNLib
nie tylko udało mi się skończyć* moduł eNLib, ale również opublikować w PowerShell Gallery. przy okazji tego drobnego sukcesu chciałem podzielić się kilkoma doświadczeniami z pisania modułów. wszędobylska zasada Pareto (lub dla bardziej dociekliwych – prawo Zipfa) okazała się sporym wyzwaniem – im bliżej końca, tym trudniej. dla tego słowo opisu samej biblioteki, oraz z czym były największe problemy przy jego wykończeniu.
tak, że teraz instalacja biblioteki sprowadza się do trywialnego 'install-module eNLib’ a źródła można również pobrać z GitHub.
[*skończyć w metodyce CI/CD, czyli najważniejsze gotowe, a z resztą jakoś to będzie (; ]
eNLib
typowa biblioteka użytkowa – kiedy skryptów pisze się dużo, bardzo szybko okazuje się, że pewne funkcje ułatwiające życie, wykorzystuje się w niemal każdym skrypcie. dla mnie taką funkcją jest write-log – funkcja, która forkuje wszelkie informacje zarówno na ekran jak do pliq. dzięki temu nie muszę zastanawiać się nad 'verbose’ [który ma swoje wady] i mam gwarancję, że wszystko co widzę, będzie również w logu. koniec zastanawiania się, że jakiś błąd śmignął na ekranie i nie wiadomo co to. łatwiej też troubleshootować – 'prześlij mi log z przebiegu’ i wszystko będzie jasne.
żeby logować do pliq, należy go zainicjalizować. i z tym było najwięcej zabawy, o czym za chwilę. drugą (czy też raczej zerową) funkcją, jest zatem start-logging, inicjalizująca zmienną $logFile i sam plik logu. jeśli wywoła się write-log bez uprzedniej inicjalizacji – zostanie automatycznie wykonana. wywołanie jawne pozwala na użycie dodatkowych atrybutów – założenie logu o zadanej nazwie, w zadanym folderze lub w katalogu 'documents’ użytkownika.
każdy plik logu zawiera podstawowe informacje dot. środowiska uruchomieniowego, każdy wpis ma timestamp a dodatkowo można tagować linijki błędów/ostrzeżeń/ok przy pomocy parametru 'type’ – nie tylko pokazuje w innym kolorze, co pomaga podczas pracy bieżącej, ale dodaje tak 'ERROR:’ czy 'INFO:’ w logu, pomagając przeszukiwać go później:
jasna sprawa, jako wiadomość można podać dowolny obiekt, który zostanie skonwertowany do tekstu. szczegóły oraz przykłady użycia – 'man write-log -examples’, 'man start-logging -full’ – więc nie rozpisuję się.
ponadto moduł zawiera funkcje
te funkcje są wersjach słabo przetestowanych i na pewno nie są dopieszczone tak jak write-log, którego po prostu używam nagminnie [już nawet odruchowo wpisuje wrtite-log zamiast write-host (; ]. na pewno powoli będę nad nimi pracował – skoro są opublikowane, to będą potrzebowały trochę więcej atencji.
Z czym było najwięcej zabawy?
przyjąłem default, że plik logu będzie miał nazwę '_<nazwa-skryptu>-<datestamp>.log’ . i żeby ową nazwę skryptu pobrać, trzeba zastosować inną metodę, zależnie od kontekstu – opisanego wyżej. 3ci opisany przypdek, choć wydaje się być najbardziej złożony, jest równocześnie domyślnym:
zmienne typu $MyInvocation to zmienne automatyczne, tworzone w trakcie egzekucji skryptu. maja więc określony kontekst, czy też zakres (scope) i w każdym będą miały inną, lokalną wartość. do tego nie można założyć konkretnego scenariusza – muszą być obsłużone wszystkie. z tego powodu kawałek inicjalizacji musiał zostać przeniesiony do samego write-log, choć łamie to logikę [powinno być wszystko w start-logging]:
2o/8o