Skip to Content

IT nieuczesane.
category

Category: DevOps/Scripting

skrypty, programy, command line i inne

szybkie wyszukiwanie plików w PowerShell

Windows_PowerShell_iconjest kilka takich narzędzi commanline w Linux, których braqje w Windows. jednym jest ‚du’ czyli Disk Usage liczący wielkość katalogu. to można sobie łatwo oprogramować:

to oczywiście na szybko, można to upiększać, dodać skrypt dostępny globalnie – prościzna. drugim bardzo często narzędziem, z którego często korzystałem było ‚locate’. w Linuxie super przydatne głównie z tego powodu, że każde distro się różni i pliki są rozpizgane po setkach katalogów. Linuxowa masakra. ale locate przeważnie jest a to poważnie ułatwia życie. idea jest taka sama jak w Windows – działa sobie indexer, który skanuje katalogi i tworzy indexy dla pliqw. można go wymusić do odświeżenia przy pomocy ‚updatedb’. w Windows jest ‚Windows Search’, czyli WSearch [w wXP był Indexing Service]. problem polega na tym, że nie ma standardowych narzędzi commandline. co prawda jest od jakiegoś czasu moduł WindowsSearch ale służy wyłącznie do konfiguracji usługi. w starym Windows Desktop Search był trick na skorzystanie z linii poleceń. jeśli jest w nowej wersji – nie znam go.

oczywiście jest API. a to daje możliwość oprogramowania sobie searcher. doqmentacja dot. tworzenia zapytań jest na MSDN. a przykładowy draft skryptu tu:

locate-File.ps1

to oczywiście wersja robocza. proof of concept. napisane tak, żeby zwracało ładne obiekty. ogólna idea to podłączenie się do bazy zawierającej indexy przy pomocy ADO i wykonanie kwerendy. wyniki podawane są niemal natychmiast tylko trzeba pamiętać, że są tam wyłącznie katalogi zindexowane – jeśli chcemy móc wyszukiwać po całym dysq, to trzeba dodać cały dysk do indexowania…

…a jeśli nie zależy nam na czasie to można szukać ‚po staremu’:

eN.

 

 

wyszukiwanie plików

scenariusz: należy wyszukać na dysq wszystkie pliki o zadanych rozszerzeniach. te zindexowane i niezindexowane.

ls (get-childitem)

  • recurse: wyszukiwanie reqrsywne po wszystkich katalogach z podkatalogami
  • force: również katalogi systemowe i ukryte
  • ea: ErrorAction – wyłączenie wypluwania błędów w razie braq dostępu

match: nie trzeba podawać oddzielnie np. docx i doc, ponieważ match ‚docx’ zawiera ‚doc’ – to jest dopasowanie ciągu a nie równanie.

export-csv

  • delimiter: przyzwyczajenie, do przeglądania w excelu
  • notype: noTypeInformation – nie dodaje śmiecia w pierwszej linijce

eN.

podgląd eventlogu na żywo i reperacja skrzynek exchange

Windows_PowerShell_iconscenariusz

rozjechały się skrzynki na exchange. trzeba posprawdzać bazy oraz zreperować, co się da, z podglądem tego, co się dzieje w danym momencie.

podstawa

do weryfikacji i naprawy mailboxów online służy New-MailboxRepairRequest. problem polega na tym, że to polecenie nie generuje logu tylko wrzuca informacje do eventvwr. ta zmiana jest określana miałem ‚alleluja, teraz jest zajebiście’ ale przeglądanie eventvwr, zwłaszcza na żywym systemie nie jest przyjemna – ani nie wiadomo kiedy co się kończy, co zaczyna, zdarzeń jest od groma, żądanie zrobione z linii poleceń, a weryfikacja w taki sposób… no generalnie słabe.

cel

byłoby fajnie móc mieć podgląd life na konsoli tego, jak przebiegają testy. zwłaszcza, jeśli chcemy co jakiś czas zapuścić weryfikację kolejnej ‚podejrzanej’ skrzynki.

rozwiązanie

znalazłem w netcie kilka lamerskich skryptów, do podglądu eventvwr na żywo (-> keyword ‚tail eventvwr’). czemu lamerskich? ponieważ działają na zasadzie nieskończonej pętli while($true) co już samo w sobie jest bolesne. w tej pętli co 1 sek pobierane jest ostatnie zdarzenie z logu aplikacji. czyli jeśli system jest na prawdę dociążony (a exchange potrafi taki być), może się okazać, że nie zobaczymy tego, na co czekamy. krótko mówiąc – DA SIĘ LEPIEJ (:

rozwiązaniem jest zastawienie pułapki – to nie my pytamy się logu o ostatni event, tylko niech log nam powie, że takowy się pojawił. kwestie wydajności pomijam bo nie badałem – na pewno trzeba pamiętać o wyrejestrowaniu pułapki, żeby nie dociążać systemu. mechanizmem, który to realizuje jest ‚register-ObjectEvent‚, który rejestruje pułapkę na przechwycenie zdarzenia dla obiektów .NET.

oczywiście nie każde polecenie zdarzenia generuje /: aby to sprawdzić, wystarczy zwykły get-member. sprawdźmy dla get-eventlog:

no i słabo – niby jest ‚disposed’ ale to nic nie daje. a to dla tego, że obiektem, który jest zwrócony, jest konkretny ‚event’. jest jednak wywołanie polecenia, które ‚podłącza się’ do eventlogu a nie do jego zawartości:

bingo! tu pojawia się ‚entryWritten’! a więc zarejestrujmy pułapkę, przefiltrujmy zdarzenia, które nas interesują – i jeśli takowe się pojawi, wyświetlmy na ekran. opis eventów, jakie generuje new-mailboxrepairrequset można znaleźć na technecie. poniżej draft skryptu, który można sobie dowolnie rozbudować. dla czytelności zapisany w kilq linijkach.

na początq podłączamy się do konkretnego logu – logu aplikacji. następnie dla tego logu rejestrujemy pułapkę na pojawienie się nowych zdarzeń i definiujemy akcję. ponieważ na poziomie rejestracji nie ma możliwości zdefiniowania żadnych filtrów, wszystko trzeba zdefiniować wewnątrz ciała skryptu. po dokonaniu rejestracji, w konsoli będą się pokazywać wszystkie logi pomiędzy 10041-10062. oczywiście warto je ładniej wyświetlić i zrobić pełną obsługę… aby tego dokonać, kluczowym jest obiekt $event.SourceEventArgs.Entry, który jest de facto eventem pojawiającym się w logu, czyli można dostać się do wszystkich parametrów takich jak przy ‚ Get-EventLog -LogName application -Newest 1 |gm’.

na koniec trzeba pamiętać o wyrejestrowaniu!! na skróty, wyrejestrowanie wszystkich:

eN.

 

 

 

splatting – dynamiczna budowa parametrów wywołania

jak to często bywa, bardzo-długa-polska-nazwa ma krótki odpowiednik (; „Splatting” to mechanizm, pozwalający na zbudowanie zmiennej hashtable, która zostanie wykorzystana w miejsce tradycyjnych parametrów wywołania. po co?

bardzo często finalne parametry wywołania jakiegoś polecenia zależą od tego, co się wydarzy podczas przetwarzania skryptu. w efekcie często powstają złożone, a czasem wręcz zagnieżdżone, struktury ‚if-then-else’ lub ‚switch-case’. dodanie kolejnego warunku powoduje, że modyfikacja skryptu staje się nieprzyjemna lub wręcz ryzykowna, bo wymaga ciężkiego przebudowania logiki. splatting eliminuje  konieczność budowania takich dziwacznych struktur.

zademonstruję to na prostym przykładzie – założenia użytkownika. taki scenariusz: dostajemy arkusz z listą użytkowników z kilq działów. pewne dane, takie jak telefon czy adres nie są obligatoryjne i czasem są a czasem nie. w przypadq ‚new-ADUser’ splatting nie pokazuje prawdziwej mocy, ponieważ większość parametrów przyjmuje ‚$null’ jako wartość, więc przy stałym finalnym wywołaniu, polecenie nie spowoduje błędów. ale to tylko trening:

jest wiele poleceń, które nie będą takie przyjemne, i $null zostanie zaakceptowany lub wręcz będzie miał jakieś znaczenie. jak zatem pozbyć się takich pustych parametrów podczas przetwarzania i zbudować dynamiczną listę wywołania?

dwie ważne rzeczy:

  • przy przekazywaniu tablicy jako parametrów używa się ‚at’ @ zamiast dolara ‚$’. dość wyjątkowe użycie – trzeba zapamiętać.
  • splatting można wykorzystać nawet tam, gdzie commandlet/funkcja nie ma zdefiniowanego przyjmowania wartości ‚by value’. czyli można zawsze – to modyfikacja interpretacji polecenia a nie jego właściwego wykonania.

eN.

tablica tablic

jak w PS utworzyć tablicę tablic (np. znaków)? czyli tak, aby każdy element tablicy był kolejną tablicą znaków.

zadanie wydawałoby się trywialne… ale jest drobny myk, na którym można stracić czas. problem polega na tym, że jeśli element tablic są tego samego typu, to dodając je do tablicy, zamiast tworzyć oddzielne rekordy, są sklejane.

przykład:

czyli źle – zamiast zrobić dwuelementową tablicę, gdzie każdym elementem jest inna, 3-elementowa tablica, zostały one sklejone w 6-elementową tablicę znaków. tak samo się zachowa czy są cyfry czy znaki alfabetu. zachowanie dobre, bo zazwyczaj takiej właśnie operacji się oczeqje. ale jak zmusić aby była to tablica tablic?

trik polega na zmuszeniu PS do zrozumienia, że dodawany element ma być jako całość oddzielnym rekordem tablicy. robi się przy pomocy przecinka:

choć wynik wygląda pozornie tak samo, kiedy sprawdzi się ilość elementów tablicy – są dwa. get-member pokazuje, że każdy z nich jest tablicą.

eN.

 

 

raportowanie Hyper-v Replica

taki ciekawy skrypcik

eN.

default output

Windows_PowerShell_icondefault output

po napisaniu skryptu dobrze jest móc z niego korzystać zarówno z konsoli jak dodać go do np. do schedulera. w końcu to automatyzacja. taka uniwersalność wiąże się z odpowiednim oprogramowaniem tego, gdzie trafia output. PS daje wiele możliwości tego gdzie możemy wysłać dane… ale nie na przedefiniowanie ‚output-default’. w związq z tym pisze się nadmiarowy kod ‚jeśli ekran to wywal na ekran, jeśli log, to wywal do logu’. zazwyczaj pisałem funkcję wspierającą, która to załatwia. coś w tym rodzaju:

to nie jest w pełni działający kod i ma tyle wad, że ciężko zliczyć. zależnie od przekazywanej zmiennej zachowa się inaczej w porywach do ‚nie zadziała’.

jak to zrobić PowerShell-way

są dwa mechanizmy, które pozwalają na uproszczenie całej procedury: aliasy oraz możliwość przedefiniowania standardowej wartości parametru dla commandletu. sam alias nie wystarczy bo o ile out-host nic nie potrzebuje o tyle przekierowanie do pliq wymaga co najmniej nazwy tego pliq…

w skrócie:

w zależności od przełącznika ‚log’ tworzony jest alias ‚out-my’ wskazujący albo na out-host albo na out-file. ponieważ out-file wymaga podania nazwy pliq, aby można było użyć aliasu bez parametru, ustawiona jest standardowa wartość poprzez $PSDefaultParameterValue

eN.

 

niedefaultowy default – import-csv

Windows_PowerShell_iconjedną z częściej wykorzystywanych przeze mnie funkcji jest import-csv/export-csv – praca na tabelkach, zestawienia, raporty, statystyki… ponieważ środowisko jest wielojęzyczne, standardowym problem jest kodowanie znaków. bardzo często kiedy wydaje mi się, że już skończyłem – nagle okazuje się, że mam w nazwach kwadraciki czy znaki zapytania…

od #PS3.o funkcje csv zostały uzbrojone w parametr ‚encoding’:

pojawia się tu wartość ‚Default’ oraz informacja że ‚default is ASCII’. to jest pewna zdrada – niekoniecznie intuicyjne zachowanie. wywołanie import-csv bez wartości ‚encoding’ przyjmie wartość ‚ASCII’. a uruchomienie „import-csv -encoding Default” … przyjmie wartość ‚system default’ – co zazwyczaj będzie oznaczało Windows ANSI dla ustawionego języka.

do zapamiętania: podczas exportu z Excel, używany jest właśnie ‚system default’ czyli zazwyczaj ANSI . używając import-csv/export-csv należy używać ‚-encoding Default’ ponieważ … nie jest to default q:
eN.

WMI vs CIM w praktyce

Windows_PowerShell_iconzakładam, że wszyscy wiedzą czym jest WMI i CIM – to jest abecadło dla każdego inżyniera systemowego. a [IMHO] podstawowa różnica w implementacji to możliwość tworzenia sesji CIM. czego dla WMI zrobić się nie dało. daje to niesamowite możliwości w przypadq hurtowych zapytań. podam trywialny przykład, gdzie zysk z zastosowania sesji nie jest wielki, ale osoby z wyobraźnią powinny poczuć moc, drzemiącą w takim zastosowaniu.

założeniem przykładu jest sztywna notacja nazewnicza dla hostów: ta sama nazwa ‚HOST’, zakończona inkrementowaną liczbą. ale równie dobrze można użyć ‚cat lista.txt | %‚ . niemniej chciałem przy okazji przemycić jeszcze jedną sztuczkę – w jaki sposób dopełniać liczby z dopełnieniem zerami.

cel: odpytanie 2o hostów o podstawowe informacje o BIOS – np. numer seryjny – oraz volumeny.

dla WMI

teraz zmierzmy czas dla wykonania tej sekwencji [ja robiłem dla siedmiu hostów]:

 

dla CIM

wydaje się być bardziej skomplikowane. odrobinę jest – trzeba najpierw założyć sesje, a następnie wykonać zapytanie wskazując na nie. sprawdźmy ekonomiczność zapytania [również dla 7 hostów]:

1331 vs 263  ms czyli 5cio krotnie szybciej [SIC!]. oczywiście można się przyczepić, że nie wliczyłem czasu utworzenia samej sesji ale…

wnioski

przy pojedynczym zapytaniu lub do niewielkiej ilości hostów – nie ma znaczenia czego użyjemy, bo czy co się wykona w 4oms czy w 1ooms jest dla człowieka pomijalne. jednak możliwość tworzenia sesji zwraca się przy seryjnych odpytaniach oraz jeśli do odpytania jest wiele hostów.

warto zauważyć, że przy dłuższej pracy zapis się upraszcza – ponieważ zamiast na iteracjach czy listingach, pracujemy na liście sesji.

eN.

 

 

PowerShell – nauka na błędach cz.IV.

Windows_PowerShell_iconna koniec samo ciało skryptu. logika.

pierwotny skrypt składa się w 2o% z komentarzy [dokumentacja] oraz 8o% z ciała skryptu zmieszanego z deklaracjami [management]. takie statystyki oznaczają jedno – to jest źle napisany skrypt. obecna wersja to [ok.] 27% komentarzy [dokumentacja], 18% deklaracje [magazyn danych], 4o% w funkcjach [siła robocza] oraz 15% ciała [management]. to oznacza, że:

  • jest jasna izolacja bloków kodu co zwiększa przejrzystość i wydziela zakresy odpowiedzialności
  • skrypt jest lepiej opisany,
  • duża część kodu może być wielokrotnie wykorzystana
  • a samo ciało zajmuje się wyłącznie zarządzaniem – niezbędna logika sterująca funkcjami [siłą roboczą] które z kolei korzystają ze zmiennych [magazyn].

dodam jeszcze, że całkiem przypadkiem, oba skrypty mają [u mnie] identyczną ilość linii.

deklaracje już były, pozostaje zatem do przedstawienia sama logika [silnik]:

i to wszystko.

ogólna idea jest bardzo prosta – zależnie od wybranego zakresu [$scope] wykonywane jest wyszukiwanie przy pomocy funkcji ‚doTheSearch’, opisanej w poprzedniej części. funkcji przekazywane są wszystkie niezbędne zmienne – informacja o rodzaju obiektu, definicja filtru oraz nazwa pliq wyjściowego, która jest zależna od typu wyszukiwania. jedyne, co jest nietypowe, to wykorzystanie prostych wyrażeń regularnych.

dzięki temu, że switch pozwala na wykorzystanie regex, można zastąpić wiele linijek ifów i elsifów bardzo kompaktowym zapisem – jak na załączonym obrazq. oznacza to, że podczas decyzji wykonywany jest $scope -match <regex> – czyli jeśli wpada parametr ‚Users’ to:

‚Users’ -match ‚nonExpiring OR all’ -> false
‚Users’ -match ‚Users OR all’ -> true, wykonaj kod

jeśli $scope jest równy ‚all’ – wpadnie we wszystkie zdefiniowane przypadki. wygodne.

obiecałem wyjaśnić bardziej złożone wyrażenie regularne, z poprzedniej części:

WTF? otóż te dwie linijki zastępują brzydkie, wielokrotne porównania, przyspieszając wyszukiwanie wartości w macierzy:

‚match’ jest ostatnio moim ulubionym operatorem. zastępuje -like ‚*coś*’ ale co ważniejsze – wyszuqje w macierzach. prosty przykład użycia przedstawiałem a propos wyszukiwania podstawowego adresu email. jest prosty, zastępuje bezsensowne pętle i … jest super szybki – nawet o rząd wielkości szybszy niż zastosowanie pętli. oczywiście nie ma to znaczenia jeśli w tablicy są 3 elementy – jak w tym przykładzie, ale jeśli ilość idzie w tysiące, zaczyna to odgrywać poważną rolę. a tutaj – po prostu jest geekowe =^.^’=

[regex]::escape($string) warto zapamiętać – jest to automat ‚escapeujący’ wszystkie znaki specjalne – kropki, przecinki, znaki z poza zakresu, slashe itd. dzięki temu cokolwiek by było w nazwie – zostanie automatycznie zmienione na string z pojedynczą interpretacją. w efekcie powstanie zwykły regex [widać wyescapeowane spacje]:

w efekcie wykonywane jest proste porównanie – „jeśli w distinguishedName znajdziesz którąkolwiek z wartości w $ouRX to…” i pozamiatane. warto zwrócić uwagę, że taka odwrócona logika jest bardziej ludzka, bo przedstawioną pętlę można przeczytać jako: „dla każdego elementu z $ouToSkip sprawdź, czy nie występuje gdzieś w distinguishedName. jeśli tak to…”, co nie jest po naszemu.

każda opowieść ma swój finał. ta kończy się w ten sposób:

download: find-UnusedADObjects

eN.

 

 

 

 

 

%d bloggers like this: