Skip to Content

IT nieuczesane.
category

Category: DevOps/Scripting

skrypty, programy, command line i inne

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

Windows_PowerShell_icondziś ‚jeśli jakiś kod się powtarza – to najprawdopodobniej da się to zoptymalizować’. czyli funkcje.

w wyjściowym skrypcie szybko można zauważyć, że zarówno dla obiektu user oraz computer operacje są niemal identyczne. oczywiście są niektóre parametry w AD, które są dla tych obiektów bardzo różne, jednak albo nie są tu potrzebne albo można przeżyć jeśli będzie zwrócony null. a zatem można utworzyć pojedyncze zapytanie i wykorzystać je kilka razy.

samo query można by zrobić przy pomocy uniwersalnego get-ADObject… jednak z jakiegoś powodu nie przyjmowało wybranych atrybutów [$properties]. zamiast debugować zastosowane zostało obejście problemu. polecenie jest złożone jako string a następnie wywołane. funkcja przyjmuje trzy parametry, m.in. $type. czyli wykonanie „get-ad$type” rozwiązuje problem. aby wykonać ciąg jako polecenie należy skorzystać z ‚invoke-Expression’.
get-ad* zwraca kolekcję obiektów. każdy taki obiekt będzie obrobiony przy pomocy funkcji ‚prepareADObject’ przedstawionej za chwilę i wrzucony do tablicy $resultList. taki sposób ma dwie zalety – przenosi obróbkę obiektu do oddzielnego bloq, dzięki czemu w przyszłości łatwo będzie coś sobie zmodyfikować, natomiast listę na koniec łatwo będzie wyeksportować… albo jeśli zajdzie potrzeba – zastosować dodatkowe filtry. co się zresztą za chwilę dzieje.

jeśli zmusiliśmy skrypt przełącznikiem ‚$toScreen’ do tego, aby od razu wypisać na ekran zamiast do pliq, to w tym momencie zostanie wypluta na standardowe wyjście lista. na tej liście, co będzie widoczne po obejrzeniu funkcji ‚prepareADObject’, są obiekty. jest to istotne ze względu na, nomen omen, istotę całego PowerShell. jego potęga tkwi w tym, że [niemal] wszystko co wypluwa i przyjmuje jest obiektem. dzięki temu można tworzyć wielkie rurociągi aka oneliners – przekazując obiekty do obróbki do następnego polecenia|do obróbki do następnego|do obróbki… | aż na zdefiniowane wyjście. dla tego dobrą manierą pisania skryptów, jest definiowanie i wypluwanie obiektów, dzięki czemu wyjście naszych własnych skryptów również może być dalej obrabiane standardowymi narzędziami:

kolejną rzeczą jest plik wyjściowy. od wieków ‚comma delimited’ jest przez Excel rozumiany jako ‚semicolon delimited’, więc aby plik wyjściowy był automatycznie raportem Excel, wystarczy wypluć go jako csv oddzielany średnikiem:

można bawić się oczywiście w obiekty COM i bezpośrednie tworzenie xlsx … ale po co? formatowanie tabeli w Excelu robi się w 3 sekundy. największym problemem byłoby to, że taki obiekt musi istnieć w systemie, w którym uruchamia się skrypt – a na serwerach instalacja Excel… słabe wymaganie, do uruchomienia małego skryptu. csv zamyka temat tworzenia raportu.

dalej widać zaletę utworzenia własnej listy, co było wspominane. ponieważ jest przetrzymywana w zmiennej można ją kilqkrotnie wykorzystać. jeśli raport ma być rozbity na kilka pliqw – proszę bardzo. kilka linijek kodu i zostanie przefiltrowany – zrobienie dodatkowych zapytań do AD byłoby dużo wolniejsze.

ostatnią rzeczą na jaką warto zwrócić uwagę jest specyficzne wykorzystanie zmiennej – $script:usedFiles. sama zmienna posłuży do qlturalnego wyświetlenia na koniec wszystkich wyplutych  pliqw. wykorzystanie słowa kluczowego ‚$script:’ zmusza/informuje interpreter, że zmiany mają być zapisywane w zmiennej globalnej dla skryptu – jak zajrzycie do poprzedniego odcinka zobaczycie, że gdzieś tam, na początq była deklaracja $usedFiles=”” . przy pewnych zagnieżdżeniach, w szczególności przy rekursywnych wywołaniach, kontext zmiennej jest gubiony więc trzeba go usztywnić.
można również odwołać się do zmiennej globalnej dla środowiska [czyli z poza skryptu] poprzez wykorzystanie ‚$global:’

teraz chwilę o własnych obiektach. jest to istną tajemnicą, czemu w języq tak silnie obiektowym, nie ma klas. są dwie protezy – jednej nie będę opisywał, ponieważ umrze wraz PS5.o, a najczęściej stosuje się po prostu tworzenie obiektu bez klasy. potwornie niewygodne i mało intuicyjne… ale cóż. jak się nie ma co się lubi to:

 

skoro get-ad<typ> wypluwa obiekty, to czemu męczę się ze zrobieniem własnego obiektu, zamiast zastosować select albo inny natywny dla języka sposób? odp: ponieważ daje to potężne narzędzie obróbki – ot choćby zmianę daty na zrozumiałą przez istotę gatunq homo sapiens. mogę też dodawać własne atrybuty, których nie ma w oryginale – np. ‚skip’. ten atrybut jest istotny dla raportu oraz wszelakiego filtrowania. w założeniach skryptu była informacja, aby obiekty ze zdefiniowanych OU były wyszukiwane, ale oznaczone. w pierwotnej wersji dostawiana była na początq linii ‚*’ [fujć!]. dzięki dodaniu kolumny ‚skip’ można po otwarciu pliq w excelu bardzo łatwo zrobić filtrowanie… a nie jakieś tam gwiazdki i operacje na stringach… tu się, psze państwa, pracuje na obiektach q:

samo ustawienie atrybutu skip na $true jest lekko zagmatwane… pozostawię sobie pełne tłumaczenie na następny, ostatni wpis cyklu, gdzie postaram się dokładnie wyjaśnić to wyrażenie regularne i jak powstało.

w poprzedniej części była deklaracja zmiennych i komentarze, w tej – funkcje wspierające. pozostało opisanie ‚ciała’ skryptu. jak sądzicie – jak dużo będzie tego ciała? (;

eN.

 

PowerShell – nauka na błędach cz.II

Windows_PowerShell_iconna początek zaprezentuję… początek. całkiem logicznie q:

find-UnusedADObjects.ps1

po pierwsze nazwa skryptu z przyjętą w PS notacją. korzyść – bardziej intuicyjne wykorzystanie.

po drugie bardziej rozbudowane komentarze. odpowiednio zrobione są bardzo wygodne – korzystając z polecenia get-help wyświetli się pełny opis. każda wersja PS wprowadza coraz więcej obsługiwanych słów kluczowych, a żeby dowiedzieć się o całości należy poszukać ‚comment based help‚. niektórzy mogą powiedzieć – ‚eeee, jestem zbyt leniwy na takie szlaczki’.  zatem zwróćcie uwagę na to, jak opisany jest parametr ‚scope’ a jak ‚splitFiles’:

  • ‚scope’ jest wyniesiony na początek , do ‚comment based help’
  • ‚splitFiles’ jest opisany ‚na lenia’ jako komentarze tuż pod opcją

obie wersje są obsługiwane przez get-help, więc jak się okazuje – nawet nie trzeba rysować szlaczków. wystarczy minimum wysiłq aby na szybko opisać po co jest dany parametr – z korzyścią dla twórcy jak i dla end-usera.

jest jeszcze jedna metoda tworzenia komentarzy, ale wydaje mi się, że to jeden z pomysłów, który się nie przyjął i został porzucony. jego zastosowanie jest, delikatnie mówiąc, niszowe:

wiadomość można zobaczyć na dwa sposoby – badając kod źródłowy skryptu, lub:

jeśli wartość zdefiniowana jest jako obligatoryjna ORAZ nie wprowadzimy jej ORAZ po wyświetleniu komunikatu wpiszemy ‚!?’ [SIC!]:

wygląda na to, że ktoś miał pomysł… tylko inni go nie podzielili (;

„#Required -version 3” zapewnia kompatybilność. nie bawiłem się w ładowanie modułów bo zakładam, że zostaną załadowane automatycznie [od ver. PS3.o] oraz wykorzystane jest kilka technik zapisu, które nie jestem pewien czy zadziałają w PS2.o. to zabezpieczy przed przypadkowym odpaleniem na starej wersji.

następnie parametry. nie tylko są, ale są zdefiniowane w bardziej rozbudowany sposób – część z nich ma określone ograniczenia poprzez validateSet i validateRange. to kolejna rzecz, która nie służy wyłącznie dla zaspokojenia puryzmu i widzi-mi-się. jedną z najwygodniejszych cech PS jest dokończanie TABem. jeśli zdefiniowany jest validateSet, to szybko można całe polecenie wpisać: „find-u<TAB dokończy nazwę skryptu> –s<TAB dokończy nazwę parametru> <TAB będzie przerzucał pomiędzy zdefiniowanymi wartościami>”. takie niuanse są prawdziwą SiłąPowłoki (;

inną ciekawostką jest zdefiniowane zmiennej, której standardowa deklaracja jest kawałkiem kodu:

zacznę od tego, że jestem przeciwnikiem takiego pisania – braqje tu obsługi błędów. ale w całym skrypcie darowałem sobie obsługę błędów – zupełnie nieedukacyjnie… ale to na inny wpis, kiedyś. drugi błąd popełniony w tej linijce to wykorzystanie aliasu ‚gc’. aliasy mogą być globalnie przedefiniowane więc dla pewności w skryptach powinno się ładnie używać pełnych, prawidłowych nazw commandletów. trzecią ‚głupią’ rzeczą, której w praktyce nie robię i jest tutaj bardziej do celów edukacyjnych, jest wyniesienie zmiennych do oddzielnego pliq.

find-UnusedADObjects.OUsToSkip

w starej wersji pliq było wewnątrz: $OUsToSkip=”Servers”,”_UnusedObjects”,”Service Accounts”  . kiedy należy wynieść wartości do zewnętrznego pliq? kiedy skrypt będzie zaszyfrowany lub podpisany certyfikatem. czyli nie będzie można w nim dokonać żadnej modyfikacji. należy wtedy jednak dobrze opisać w helpie jak taki plik ma się nazywać, co ma zawierać itd. sporo problemu. a ponieważ zazwyczaj celowo oddaję źródła, zależy mi na ‚kompaktowości’ rozwiązania – potęga skryptów to często fakt,  że jest to *pojedynczy*, mały plik.  niemniej warto wiedzieć, że tak również można zrobić, i to w całkiem prosty sposób.
oczywiście oprócz pliq można po prostu podać tablicę stringów jako parametr… ale niezbyt to wygodne w codziennym użyciu.

kolejne drobiazgi w deklaracjach to np. fakt, że pliki będą się odkładać a nie nadpisywać, ponieważ zawierają datę w nazwie.

dalej widać regex który omówię w późniejszych częściach, deklaracje filtrów wyszukiwania, $searchProperties – które, jak się finalnie okaże, wyniesione w tym miejscu pozwoli w bardzo łatwy i szybki sposób poszerzyć funkcjonalność, jeśli klient nagle zażyczy sobie w raporcie dodatkowych danych.

i to na tyle w tej części. niby tylko ‚komentarze i deklaracja zmiennych’ a okazuje się, że już w tej fazie, jest wiele istotnych detali na które należy zwrócić uwagę aby skrypt był wygodny w użyciu i przejrzysty.

eN.

 

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

Windows_PowerShell_iconmoje skrypty gdzieś tam sobie żyją u różnych klientów. dostałem ostatnio prośbę, aby coś tam w jednym takim skrypcie zmienić. otworzyłem, popatrzyłem.. popłakałem się i napisałem go od nowa.

skrypt był z 2o11 – kiedy uczyłem się PS. na pierwszy rzut oka można stwierdzić, że jest napisany przez kogoś, kto pisał w VBSie i właśnie zaczyna się uczyć się składni PS i daleko jeszcze do Zrozumienia tego języka. skrypt działał i był regularnie wykorzystywany przez kilka lat – ok. pod tym względem ok. ale to, w jaki sposób jest napisany… po prostu musiałem napisać go od nowa.

przypatrzmy się temu… temu.. tej atrapie skryptu. tak na prawdę to trzem skryptom, stanowiącym mechanizm pozwalający robić regularny przegląd AD – nieużywane konta użytkowników, komputerów oraz konta z niewygasającymi hasłami. całość ma pozwolić na:

  • znalezienie nieużywanych obiektów
  • możliwość przejrzenia ich tak, aby admin mógł ręcznie odfiltrować co jest potrzebne a co nie
  • przygotowanie danych do raportu (to właśnie był nowy request po którym postanowiłem napisać całość od nowa)
  • łatwe zablokowanie takich obiektów.

zacznę od tego, co było zrobione dobrze. pewne nawyki można wynieść nawet z VBSa q:

  • skrypt jest *w miarę* uniwersalny. i faktycznie wiem, że był/jest wykorzystywany u co najmniej 3 klientów bez większych przeróbek [przynajmniej kiedy go oddawałem]
  • kod jest opisany
  • są informacje o wersjach – wbrew pozorom wielokrotnie był to istotny niuans pozwalający szybko ustalić której wersji ktoś używa, a więc co może nie działać.

w dużym skrócie – ponieważ skrypty piszę od bardzo dawna, trochę dobrych nawyków widać. jednak tu, gdzie zaczyna się znajomość języka… jakie zatem widać wady:

  • skrypt może i jest *w miarę* uniwersalny, ale to mało. zmienne powinny być wyrzucone do parametrów [których wtedy nie umiałem jeszcze używać] tak, aby nie trzeba modyfikować samego kodu.
  • już sama nazwa pliq nie jest zgodna z przyjętą przez PS notacją czasownik-rzeczownik
  • wyjściem jest plik textowy… niby ładny, bo jakieś komentarze… ale nauczyłem się, że dobry plik, to uniwersalny plik. czyli taki, który można otworzyć np. w excelu i dowolnie go obrobić. dzięki temu format staje się przenośny i pozwala wykorzystywać różne wbudowane w język mechanizmy, zamiast kombinować z pisaniem własnej ‚obsługi’. np. jest zmienna, definiująca OU, które mają być wyszukane, ale pominięte przy późniejszym blokowaniu. wymyśliłem więc, że będę umieszczał asteriska ‚*’ na początq linii. fujć! jakie to… VBSowe.
  • pliki wyjściowe mają zawsze tą nazwę. to oznacza, że wejściowe dla skryptu, który będzie je obrabiał, również ma ‚zahardcodowane’ nazwy. brzydka maniera, z różnych powodów [np. brak historii].
  • wykorzystywanie mechanizmów o statusie ‚obsolete’ – ADSI to stary interfejs COM… [na usprawiedliwienie mogę powiedzieć, że wtedy nie było jeszcze tak rozbudowanego modułu ActiveDirectory i wszyscy używali commandletów questa. nie jestem pewien czy pierwsze commandlety AD nie wykorzystywały ADSI?]
  • duża ilość powtórzonego kodu – zarówno dla obiektu typu user jak computer jest praktycznie ten sam kod.
  • nie są wykorzystywane dobrodziejstwa języka. kod jest mówiąc oględnie – prymitywny.

widać, że jakieś tam drobne zmiany były wprowadzane – w końcu najważniejsze jest, że działa. jednak przychodzi moment, w którym pojawia się nowe żądanie zmiany i przerobienie kodu nagle staje się zbyt pracochłonne albo po prostu niewygodne. tak też zrobiłem wiosenne porządki i napisałem skrypt od nowa…

w kolejnych częściach będę prezentował po kawałq nową wersję komentując zastosowane techniki.

eN.

 

PS ISE – cudowny trick

windows-powershell-ise-iconostatnio odkryłem cudowny trick w PowerShell Integrated Scripting Environment:

przytrzymać shift+alt i teraz:

  • poruszając się strzałkami góra/dół oraz lewo/prawo można zaznaczyć blok
  • a teraz jeszcze lepszy: poruszając się strzałkami góra/dół rysuje się pionowa linia. i teraz kiedy zaczyna się pisać we wszystkich liniach pojawiają się znaki =^.^’=  tak samo można kasować.

przydatne w wielu scenariuszach – np. w hurtowym komentowaniu fragmentu kodu.

eN.

pliki nieistniejących użytkowników

CubanCigarNonExistentFSRM [File Server Resource Manager] to całkiem przydatne narzędzie, jednak braqje w nim jednego, bardzo ważnego raportu – wyszukiwanie plików należących do kont, które już nieistnieją. nie będę zamieszczał Skryptu – pokażę tylko sposób. taki PoC. tym razem potrzebowałem to zrobić na szybko. za jakiś czas pewnie ubiorę to w porządny kod bo zostało mi jeszcze kilka serwerów a póki co ‚sposób na szybko’:

 wyjaśnienie

wylistuj całą strukturę rekursywnie. dla każdego elementu z listy zapamiętaj nazwę elementu, rozmiar i pobierz ownera. ownera można sprawdzić przy pomocy polecenia get-ACL. get-ACL automatycznie rozwiązuje nazwy SID na nazwy kont. zatem jeśli nie rozwiąże nazwy [czyli pokaże się jakieś ‚S-1-5-21…’] – user nieistnieje.

całość jest bardzo niedoskonała – to, że nazwa nie została rozwiązana, nie gwarantuje, że konto nieistnieje. mogą być np. problemy z siecią, trustami, nie pamiętam jak się zachowuje dla uprawnień nadanych dla SIDHistory… w środowisq, w którym z tego korzystam takie problemy mnie nie interesują i dopuszczalny jest margines błędu na tego rodzaju scenariusze. całość i tak idzie do analizy biomaszynowej [czyt. istotę żywą].

aby utworzyć z tego skrypt… o to jeszcze sporo roboty. kod jest pasqdnie tymczasowy – braqje parametrów, obsługi błędów a finalnie powinna być zwracana tablica obiektów, żeby można było sobie dalej robić selecty czy inne wynalazki.

uwaga na zaokrąglenia

w pierwszej wersji nie podobało mi się, że wielkość zwracana jest w bytach. w końcu MB są wygodniejsze. i tu pojawia się pytanie – gdzie wstawić zaokrąglenie? ze względów na optymalizację zapytania, wszelkie operacje matematyczne należy umieszczać jak najdalej. ponieważ w kodzie są filtry, to aby liczyć jak najmniej, warto liczyć na minimalnej liczbie obiektów. zmieniłem zatem ‚$($size)’ na ‚$([math]::round($size,2))’. zapytanie zwróciło ok. 25o.ooo wyników. po zsumowaniu wartości liczbowych wyszło mi, że te pliki zajmują w sumie 1.2GB. mało. podejrzanie mało. wpadłem w pułapkę zaokrągleń. postanowiłem zatem nie zaokrąglać, zsumować bajty i dopiero ostateczną wielkość przekonwertować na GB. że będzie różnica to byłem pewny, niemniej skala mnie powaliła. wynik wyszedł powyżej 52GB (SIC!).

eN.

 

przeszukiwanie logów aplikacyjnych

chaoschciałem zrobić szybką wrzutę na temat odczytywania zdarzeń z logu ‚applications and services logs’… i okazuje się, że to całe małe universum XMLowe…

najważniejsze informacje: logi systemowe można czytać łatwo i przyjemnie przy pomocy ‚get-EventLog’. jednak kiedy chce się odczytać coś z logów aplikacji zaczynają się schody. jest polecenie ‚Get-WinEvent‚, jednak mechanizm za nim się kryjący jest okrutnie nieprzyjemny. cała architektura oparta jest na XMLu, w związq z czym jakiekolwiek przeszukiwanie albo jest pop(*^@#!@ne albo niewydajne. przykłady filtrów XML – standardowy i xPath ze strony technet:

w dużym skrócie – jest to zupełnie nieprzydatne w zastosowaniu codziennej administracji ponieważ:

  • trzeba nie tyle ‚znać’ obsługę XML ale ‚mieć ją wkompliowaną w mózg’. jak ktoś z tego korzysta dzień w dzień, to może trzepnie taki kodzik na kolanie, ale jak raz na jakiś czas trzeba coś wyszukać…
  • nie da się na stałe zrobić zapytania, ponieważ zdarzenia mają różną strukturę – składają się z różnych elementów. jak to w XML – trzeba ‚crawlować’  po elementach, bo ich struktura nie jest z góry znana
  • dwie różne metody, dwa totalnie różne zapisy, do tego w żaden sposób nie przystające do reszty PS

a przecież XML można przedstawić za pomocą obiektu… czemu ten wynalazek nie zwraca normalnego, ludzkiego obiektu z atrybutami?

polecam art, w którym można poczytać jak się przez to przegryźć.

a na szybko, bez developerki, może niewydajnie, ale działa:

scenariusz: znaleźć logi hyper-v, w których są wpisy dotyczące maszyny o nazwie ‚VMNAME’

inne pomocnicze polecenia na początek to ‚get-WinEvent -listProvider *’ oraz ‚get-WinEvent -listLog *’. trzeba jakiś list otwarty do scripting guy’a napisać, żeby ponaciskał na uczłowieczenie dostępu do logów aplikacyjnych… ahhh.. żeby tak czas pozwolił to można własny moduł napisać… /:

eN.

 

Exchange 2o1o, PS2.o – personal quota limits

PS2.o nie ułatwia życia… no ale czasem trafia się na takie środowisko i trzeba. szybka wrzuta, bez specjalnego tłumaczenia: sprawdzić kto ma włączone własne limity skrzynkowe oraz jaka jest obecnie zajętość skrzynki, żeby wiedzieć o ile można od razu przyciąć.

w tym celu trzeba połączyć wyniki get-mailbox i get-mailboxstatistics:

get-personalQuotaLimits.ps1

ciekawostka: commandlety Ex2o1o są dostarczane jako snapin a nie moduł… ot taki archaizm.

eN.

listing przypisań ProtectionGroup-DataSource

dziś na szybko, bez tłumaczenia. skrypt get-DPMGroupToDataAssociation.ps1:

i potem można np:

get-DPMGroupToDataAssociation | select PGname,computer

eN.

Powershell i dyski maszyn wirtualnych w klastrze – kontynuacja

druga część o raportowaniu dysków na Technet

eN.

Powershell i dyski maszyn wirtualnych w klastrze

tym razem na Technet – zapraszam do lektury (:

http://blogs.technet.com/b/plitpromicrosoftcom/archive/2014/10/16/storage-capacity-report-statystyki-dysk-243-w-na-klastrze-hyper-v-i-powershell.aspx

eN.

%d bloggers like this: