Historia… inaczej.

history_bookOd jakiegoś czasu noszę się z zamiarem napisania o grupie modułów, których autorem jest Kirk Munro – jeden z niewielu ludzi, którzy tytuł PowerShell MVP noszą tak długo, że trudno oprzeć się wrażeniu, że z tytułem tym się urodzili. Kirk to dynamit, człowiek pełen pomysłów a gdy zaczyna pomysły te wprowadzać w życie… Dziś o module, który zmienia zasadniczo sposób pracy z historią poleceń.

Moduł HistoryPx przeznaczony jest dla wszystkich wersji PowerShella, począwszy od wersji trzeciej. Zmienia on w sposób zasadniczy to, jak zachowuje się nasza konsola i pozwala nam cofać się do przeszłości. Zanim jednak przyjrzymy się temu jak świat wygląda po zainstalowaniu i zaimportowaniu tego modułu, pomówmy sobie chwilę o tych wszystkich sytuacjach, gdy czegoś w PowerShellu nam brakowało…

Smutny świat bez HistoryPx

Właśnie uruchomiłeś polecenie, które łączy się z kilkoma serwerami i zbiera informację. I zbiera… I zbiera… Trwa to niemożebnie długo, wreszcie jednak pojawiać zaczynają się wyniki. Wyglądają dość dobrze. Przydałoby się je przefiltrować, pogrupować i wyeksportować do jakiegoś formatu. Ale… właśnie. Żeby dane te przefiltrować, pogrupować, ba – zwyczajnie obejrzeć ponownie sformatowane nieco inaczej, musiałabyś polecenie uruchomić ponownie, tym razem z opcją OutVariable, bądź zapisując od razu do zmiennej. Szkoda, że Ci to umknęło… Szkoda, że w PowerShellu nie da się wyświetlić wyniku ostatniego polecenia, ech…

Inna sytuacja: kilka poleceń w sekwencji. Pierwsze pobrało informacje z Active Directory. Przy pomocy drugiego udało się uzyskać informacje z SCCM. Ostatnie to już system CMDB, z którym połączyłaś się za pomocą REST. I znów: czekanie, czekanie, czekanie… Ale nie ma strachu – za pamięci ustawiłeś, że każde z tych poleceń ma ustawioną domyślną wartość OutVariable. Czyli wszystko jest w porządku! Jedna chwileczka, ale przecież drugie polecenie nadpisało wartość uzyskaną przez polecenie pierwsze, wartość drugiej „wypchnęło” polecenie trzecie… A było tak blisko! Jak świetnie byłoby móc nie tylko mieć dostęp do wyników ostatniego polecenia, ale oprócz tego do kilku poleceń wstecz… Ech, pomarzyć dobra rzecz…

Sytuacja ostatnia: kolega wpadł z prośbą o jakąś informację dwie godzinki temu. Zapisałeś mu to wszystko do pliku – po kilku podejściach, w końcu udało Ci się użyć właściwej komendy. Potem, nie pomny tego, że lepsze jest wrogiem dobrego, zacząłeś polecenie dopracowywać, dopieszczać – z marnym skutkiem. Kolega wraca właśnie z szerokim uśmiechem: wszak godzinkę temu napisałaś mu, że masz rozwiązanie. Niestety, „poprawiona” wersja nadpisała gotowy plik jakimiś śmieciami. Zaglądasz w historię i załamujesz ręce: która z kilkunastu wersji to ta prawidłowa. Żeby tak chociaż wiedzieć, które zakończyły się błędem… albo zwróciły jakąś absurdalnie małą liczbę wyników…

Nic, pozostaje zdać się na ślepy los… Disappointed smile

Piękny, nowy świat

Spójrzmy więc na świat nowy, świat w którym historia przestaje być zrzędliwym starcem, który wypomina nam stare błędy: „nie zapisałeś, nie przekierowałeś, to sobie od nowa zaczynaj” – wszystko zwieńczone urągliwym rechotem, zakończonym atakiem kaszlu. HistoryPx stanowi swoisty dyktafon lub kamerę z opcją nadpisywania rzeczy nazbyt starych. Pozwala nam z łatwością sięgać do tego, co robiliśmy i robi to w sposób zarówno wydajny jak i wyjątkowo przemyślny. Wróćmy wobec tego do naszych scenariuszy i przyjrzyjmy się temu, jak marzenia stają się rzeczywistością.

Moduł HistoryPx dodaje do naszej konsoli zmienną „__” – która aktualizuje swoją zawartość jedynie wtedy, gdy taka aktualizacja ma sens. Opcje te można zmienić, ale domyślnie zmienna ta zachowa wynik ostatniego polecenia, chyba że:

  1. Wynik będzie skalarem: stringi, liczby, daty nie „nadpisują” jej zawartości
  2. Wynik stanowi zmienną pustą ($null) – czyli wszelkie polecenia, które nie zwracają sensownych wyników, nie są uwzględniane
  3. Wynik będzie rezultatem niektórych poleceń: Format-*, Get-Help, Get-Command…
  4. Definiujemy polecenie (funkcja, workflow, filtr)
  5. Skorzystamy z operatora przypisania bądź inkrementacyjnych (++ czy –)
  6. Odniesiemy się do zawartości zmiennej (czy to korzystając z niej, czy też z metod/właściwości, które się w niej znajdują)
  7. Skorzystamy z naszej zmiennej „__” w ramach jakiegoś innego polecenia

Dla przykładu: często w pracy korzystam z modułu, dzięki któremu tworzę Pull Requesty (królestwo za poprawne i nie wywołujące krwawienia oczu tłumaczenie tego pojęcia na język ojczysty!). Na ogół zapominam o tym, by wynik tego polecenia zapisać do zmiennej. W przeszłości musiałbym najpierw stworzyć PR, a następnie ponownie go pobrać i wykonać pożądaną operację:

npr Repo Branch 'Title' 'Description'
gpr Repo
gpr Repo | Where Author -match Bartosz
$mojPr = gpr Repo | Where Author -match Bartosz
$mojPr.Show()
Set-Clipboard $mojPr.Link
view raw npr.ps1 hosted with ❤ by GitHub

Metoda Show otworzy PR w przeglądarce. Właściwość Link na ogół przesyłam do kolegów, którzy przeglądają mój kod. Jak analogiczne czynności wyglądają wtedy, gdy skorzystamy z HistoryPx? Zdecydowanie przejrzyściej i bez konieczności trzykrotnego łączenia się z końcówką REST naszego BitBucket Servera:

npr Repo Branch 'Tytuł' 'Opis'
$__.Show()
Set-Clipboard $__.Link
view raw npr2.ps1 hosted with ❤ by GitHub

Jak widać, wynik ostatniego polecenia (które wyprodukowało wynik wart utrwalenia) pozostał w zasięgu moich palców bez konieczności pobierania tych informacji, które już ostały mi przekazane.

Drugi scenariusz wiąże się z tym, jak prezentuje się historia po zainstalowaniu i zaimportowaniu HistoryPx. Mamy więc do dyspozycji w ramach tejże historii kilka dodatkowych właściwości, dzięki którym (w ograniczonym lecz konfigurowalnym zakresie) możemy też uzyskać wynik naszego polecenia. Dla przykładu – chciałbym porównać zawartość dwóch dysków. Załóżmy, że jeden miałby w założeniu być zwierciadlanym odbiciem drugiego. Na dobry początek porównajmy więc zawartość folderu nadrzędnego na obu dyskach. Skorzystamy przy tym z HistoryPx: nic nie zmusza nas, byśmy wynik listowania plików i folderów zapisywali w jakiekolwiek zmiennej:

Import-Module HistoryPx
ls e:\
ls f:\
Get-History
# Output different than usual... Output looks interesting...
# CommandId match the line numbers...
diff (Get-History -Id 2).Output (Get-History -Id 3).Output -Property Name
view raw compareLs.ps1 hosted with ❤ by GitHub

Ostatni scenariusz wymagałby tego, by historia oprócz informacji o uruchomionym poleceniu, momencie rozpoczęcia i zakończenia jego działania oraz Id tegoż polecenia, oferowała nam nieco więcej informacji. I znów – z pomocą przyjcie nam HistoryPx. Obiekt zwracany przez Get-History oferuje nam nie tylko wspomniane informacje, ale również szczegóły dotyczące wyniku polecenia, ilości błędów, czy rezultat był pozytywny czy nie oraz – rzecz szalenie istotna przy poleceniach zwracających bardzo dużo wyników, czy HistoryPx wynik nam „przycięło”:

ls -Recurse -Force C:\Windows\
# .... .... ....
Get-History -Id 1 | Format-List *
<#
Duration : 00:07:41.1907948
Success : False
Output : {addins, ADFS, appcompat, AppPatch...}
OutputCount : 217767
Error : {Access to the path 'C:\Windows\CSC\v2.0.6' is denied., Access to the path 'C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc' is denied., Access to the path
'C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5' is denied., Access to the path 'C:\Windows\System32\LogFiles\WMI\RtBackup' is
denied....}
ErrorCount : 5
OutputTruncated : True
Id : 12
CommandLine : ls -Recurse -Force C:\Windows\
ExecutionStatus : Completed
StartExecutionTime : 2017-02-08 21:48:31
EndExecutionTime : 2017-02-08 21:56:13
#>
$__.Count
<#
1000
#>

Wystarczyłoby więc sprawdzić, które z poleceń nie zwróciło błędów i odpowiednią ilość wyników a przy odrobinie szczęścia (lub odpowiednio rozległej historii utrzymywanej w naszej sesji) może nawet od razu wyświetlić wynik polecenia, które zakończyło się sukcesem. Wszystko niewielkim kosztem jedynie dzięki temu, co oferuje moduł HistoryPx.

Nadchodzi nowa era!

Mam nadzieję, że przekonałem Cię, że warto. Pora więc napisać: jak. Przede wszystkim aby uzyskać dostęp do tego modułu skorzystać możesz z PowerShell Gallery. Wówczas wystarczy zainstalować moduł HistoryPx (polecenie to zainstaluje również inny moduł Kirka – SnippetsPx – którego HistoryPx wymaga. Jeśli z jakiegoś powodu z PowerShell Gallery nie chcesz/ nie możesz skorzystać, pozostaje opcja pobrania bezpośrednio u źródła. Czy to klonując moduł (a raczej moduły) z GitHuba, czy wykorzystując składnię zaproponowaną przez autora modułu. Wszystkie opcje w jednym, zgrabnym giście:

# PowerShell Gallery
Install-Module -AllowClobber HistoryPx,SnippetPx
# -not $IsADmin
Install-Module -AllowClobber HistoryPx,SnippetPx -Scope CurrentUser
# & ([scriptblock]::Create)...
& ([scriptblock]::Create((iwr -uri http://bit.ly/Install-ModuleFromGitHub).Content)) -ModuleName HistoryPx,SnippetPx
# -not $isAdmin
& ([scriptblock]::Create((iwr -uri http://bit.ly/Install-ModuleFromGitHub).Content)) -ModuleName HistoryPx,SnippetPx -Scope CurrentUser
# git clone...
git clone https://github.com/KirkMunro/HistoryPx.git
git clone https://github.com/KirkMunro/SnippetPx.git

Po zainstalowaniu/ zaimportowaniu modułu warto też przyjrzeć się dostępnym opcjom i dostosować je do naszych potrzeb. Warto przy tym pamiętać, że przechowywanie historii wielu poleceń nie jest „darmowe” – trzeba więc zadbać o to, by z powiększaniem bufora nie przesadzić. Aby sprawdzić aktualną konfigurację skorzystamy z dwóch poleceń:

  • Get-CaptureOutputConfiguration
  • Get-ExtendedHistoryConfiguration

Pierwsze pozwoli nam ustalić jak skonfigurowana jest zmienna, w której przechowywać będziemy wynik ostatniego polecenia. Polecenie pozwoli nam ustalić jak zmienna ta się nazywa, ile obiektów będzie (maksymalnie) przechowywać, jakie typy obiektów nie będą zapisywane oraz czy zapisywane mają być proste obiekty i obiekt pusty. Drugie polecenie zwraca tylko dwa parametry: ile wpisów będzie zapisywanych i ile obiektów będzie każdorazowo (maksymalnie) zapisana. Analogicznie, opcje te zmienimy przy pomocy:

  • Set-CaptureOutputConfiguration
  • Set-ExtendedHistoryConfiguration

Każdy z parametrów stanowi parametr tych poleceń, nie trudno więc odnaleźć odpowiednią składnię, by poszczególne wartości dostosować do naszych potrzeb. W kilku prostych krokach możemy uczynić historię poleceń bardziej przydatną – myślę, że warto choć spróbować. A to nie koniec cudeniek, o których chciałbym Wam napisać. Bez obietnic i terminów (te ostatnio mam brzydki zwyczaj zaniedbywać) – wkrótce postaram się napisać o innym niezwykle przydatnym module, FormatPx.

~ - autor: Bartek Bielawski w dniu 8 lutego, 2017.

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: