Skip to Content

IT nieuczesane.

ADVANCED SCRIPTING

laboratoria – czyli skrypty, skrypciki i inne takie


   Wile osób woli uczyć się czytając przykłady. Ponieżej zamieszczam kilkanaście małych skrypcików, które urodziły się podczas gdy uczyłem się pewnych mechanizmów – czy to pewnych cech VBasic’a czy zachowania się interface’u LDAP. Każdy przykład jest krótko opisany – po co został napisany i co testuje. Na podstawie tych skryptów myślę, że spokojnie można będzie spłodzić jakiś własny wynalazek…
Poszczególne rzeczy opisane są jednokrotnie – czyli jeśli w którymś skrypciku jest jakiś mechanizm nieopisany, najprawdopodobniej wyjaśnienie znajduje się gdzieś powyżej, w opisie wcześniejszego kodu.


  1. Skrypcik został napisany w celu sprawdzenia jak w VBS’ie obsługuje się argumenty z linii poleceń.

    +———— testArgs.vbs

    —–( źródło )—–

    opis:

    • [1.] wyłączone zostaje wstrzymywanie programu w razie wystąpienia błędu. Jeśli w programie zamieszczone są jakieś funkcje, ten blok powinien znajdować się w każdej funkcji – inaczej błąd, który wystąpi, spowoduje przerwanie wykonywania bloku finkcji [patrz kolejny przykład].
    • [2.] deklaracja zmiennej ‚a’. W VB nie predefiniuje się typów zmiennych [podobnie jak w JScipcie]. Type zmiennej jest automatycznie określany kontextowo.
    • [3.] WScript.Arguments jest tablicą argumentów skryptu. Item(0) to pierwszy element tej tablicy. Jest to wyra�ne niedpatrzenie ze strony twórców VBScriptu, ponieważ powinien od zwracać nazwę samego skryptu [testArgs.vbs], tak jak jest to np. w C, C++ czy Javie.

      zmiennej ‚a‚ przyjmuje wartość stringową, występującą jako pierwszy parametr.

    • [4.] na ekran wyświetlona zostaje [wscript.echo] informacja o ilości wszystkich argumentów [wscript.arguments.count]
    • dalej w zalezności od tego czy długość argumentu jest większa od zera [czyli jest jakiś argument][if len(a)>0 then] wyświetlana jest odpowiednia informacja.

  2. Jest to w zasadzie to samo co powyżej, z kilkoma dodatkami.

    +———— testArgs2.vbs

    —–( źródło )—–

    opis:

    • [1.] o ile ‚ON ERROR...‚ może pojawić się w każdym miejscu, o tyle ‚OPTION EXPLICIT‚ musi być pierwszą linijką skryptu. Generalnie w VBS’ie nie ma obowiązku deklaracji zmiennych [Dim a]. Zostaną one automatycznie zadeklarowane w razie potrzeby. Czyli w poprzednim przykładzie linijkę 2 można było pominąć. ‚OPTION EXPLICIT‚ powoduje, że brak zadeklarowania zmiennej będzie błędem. Jest to przydatne [wręcz zalecane] w dużych skryptach w celu uniknięcia literówek, z czego mogą wyniknąć trudne do odnalezienia błędy.
    • [4.] wywołanie procedury ‚show’ zdefiniowanej w liniach 6-13. W VBS’ie są procedury [SUB] i funkcje [function]. Funkcje to procedury przyjmujące wartość.
    • we wnętrzu procedury został zmieniony kod względem poprzedniego przykładu, na bardziej poprawny – najpierw sprawdzana jest ilość parametrów, żeby uniknąć operacji na null’ach.

  3. Testowanie obsługi tablic.

    +———— testArray.vbs

    —–( źródło )—–

    opis:

    • linie 1-5 to test funkcji split(), która dzieli podany string na kawałki i tworzy z tego tablicę. Warto zwrócić uwagę, że również w tym przypadku typ zmiennej został automatycznie zkonwertowany na macierzowy – ‚arr‚ stało się tablicą. Pojawia się również funkcja trim(), która obcina puste znaki na końcu i początku stringa. ubound() zwraca ilość elementów w tablicy [tutaj 4];
    • [6.] zmiana wielkościd tablicy na 0;
    • [10.] zwiększenie wielkości tablicy [redim] z zachowaniem znajdujących się w niej elementów [preserve] o jeden, w stosunku do obecnej wielkości tablicy.
    • linie 14-21 to trochę zabawy z tablicami dwuwymiarowymi. To co jest najważniejsze to to, że powiększać z zachowaniem poprzedniego stanu [redim preserve] można tylko ostatni element macierzy.

  4. Przykład obrazujący sposób bindowania się do domeny z autoryzacją czyli podaniem usera i hasła. Taki sposób jest potrzebny jeśli bind’ujesz się z systemu poza domeną.

    +———— testAuthorization.vbs

    —–( źródło )—–

    opis:

    • przykład będzie działał tak samo dla providera LDAP jak i WinNT – obecnie wyremowana jest linijka 5, ale można zamiast niej wyremować 4.
    • użytkownik i hasło nie powinny oczywiście być w pliku – jeśli chciałoby się to wykorzystać w rzeczywistości powinno się zczytać jako argumenty.
    • [13.] to własciwe bind’owanie
    • [17.] pojawia się tu err.desciption – teoretycznie coś takiego istnieje i jest opisane w dokumentacji. W rzeczywistości to jakiś fake – nigdy mi jeszcze nie zadziałało. Panuje tu typowa regóła – chcesz mieć coś zrobione – zrób to sam.
    • [20-22]: jeśli autentykacja przebiegnie właściwie, zostają wyświetlone dwa atrybuty obiektu ‚user’ – pełna ścieżka i klasa obiektu [czyli ‚user’]
    • należy zwrócić uwagę, że w poprzednich przykładach nie pojawiało się ‚set’ – ponieważ przypisując zmiennej wartość nie korzysta się z tej funkcji. Tutaj pewne zmienne stają się referencjami do obiektów – stąd ‚set’ w momencie ustalania referencji.

  5. Tworzenie usera za pomocą providera LDAP z kilkoma parametrami.

    +———— testCreateUser.vbs

    —–( źródło )—–

    opis:

    • Jest to przykład znaleziony gdzieś w MSDN’ie w nieco zmienionej formie.
    • [4.] wywołanie procedury tworzącej urzytkownika z kilkoma parametrami. Deklaracja procedury poniżej.
    • [6-72] definicja procedury tworzącej urzytkownika. To na co warto zwrócić szczególną uwagę to:
    • [13.] obsługa błędu i pojawia się dziwny numerek. Numerów błędów trzeba szukać w MSDN’ie. Są trzy standardowe rodzaje błędów: błędy ADSI, Win32 i niewiadomo-jakie. W zależności od tego na jakim poziomie wygenerowany błąd [jaki rodzaj operacji] opisu błedu należy szukać w jednym lub drugim [search key: „Win32 error codes” oraz „error codes for ADSI”] lub być domyślnym. Najczęściej chodzi o ten trzeci rodzaj (; . Błąd zapisany jest w hexach z niewiadomo-poco-umieszczoną-literką ‚L’ na końcu. Czyli jeśli w przykładzie jest rekacja na błąd „80070035” to byłoby to zapisane „0x80070035L”. Byłoby ale nie ma, bo jest to jeden z wielu nieopisanych błędów. Czsami dobre efekty daje wpisanie błedu w googlu w postaci „80070055”. Czasami nie skutkuje nic i jest się wtedy zdanym na siebie.
    • Może kiedyś odważę się napisać jakieś memo o błędach – mam kolekcję własnych odkrytych i nieopisanych błędów :P . Generalnie jest to tragedia.
    • [17-19] to imho strata czasu. Jest tu wstawiona cała 3-linijkowa obsługa err.description, który i tak prawie zawsze jest pusty. Domyślam się, że nawet jeśli kiedyś coś zwróci [co mi się nie zdarzyło] to będzie to tak przydatne jak kalosze na sacharze.
    • kolejną sprawą jest korzystanie z polecenia print – polecenie to powinno wypisywać komunikaty na STDIO czyli zazwyczaj ekran. Mi się tego nie udało uzyskać [nie próbowałem zbyt mocno] i polecam używać ‚wscript.echo’ lub napisać własną procedurkę do obsługi.
    • Dalej już są standardowe rzeczy – err.clear po każdym miejscu, gdzie może wystąpić błąd, wypisanie błędu w razie niepowodzenia i takie tam.
    • W przykładzie MSDN’owym były 2 poważne błędy. Tu są poprawione:

      – ustawienie hasła dla stworzonego obiektu było przed komendą ‚setinfo’ – czyli próbowano zmienić hasło nieistniejącemu jeszcze obiektowi. Przeniesione na koniec kodu.
      – jeśli nazwa skryptu była pusta, program wywala się. Dodana jest linijka ‚isNull’ sprawdzająca czy ustawiona jest jakaś wartość. Tak swoją drogą aby to funkcjonowało poprawnie powinno być parsowanie i przetestowanie argumentów wejściowych…


  6. Wyświetlenie wartości różnych atrybutów obiektu domeny.

    +———— testCurrentDomain.vbs

    —–( źródło )—–

    opis:

    • jeśli komputer jest w domenie, nie musimy wypiswać całej ścieżki przy próbie bindowania się do domeny. Obiekt RootDSE załatwia to za nas – co można sprawdzić uruchamiając ten skrypt.
    • część parametrów jest opatrzona pętlą ‚for each v in NAME [...] next‚. Niektóre parametry są typu tablicowego [tu nazywa się to ‚multivalue’]. Trzeba wtedy wyświetlić pojedyńcze wartości poprzez skorzystanie z takiej właśnie pętli. Próba wyświetlenia takiego parametru w zwykły sposób zwróci błąd ‚Type mismatched’.
    • Parametry wziołem z MSDN’a [search key: „Serverless binding RootDSE”]

  7. Bindowanie WinNT bez autoryzacji. Wyłączanie konta.

    +———— testDisableAccount.vbs

    —–( źródło )—–

    opis:

    • To na co warto zwrócić uwagę – w tym przykładzie wykorzystany jest provider WinNT [co się wiąże z innym zapisem], i podczas bindowania do domeny nie podawana jest nazwa użytkownika ani hasło – w takim wypadku użyte zostaną dane [credentials] o obecnie zalogowanym userze.
    • brak jest obslugi błędów. Dodane jedynie wypisywanie kropki po karzedej wykonanej operacji – czyli jeśli program się wywali, można na podstawie ich ilości dojść do miejsca wystąpienia błędu.

  8. Proste operacje na pliku

    +———— testFile.vbs

    —–( źródło )—–

    opis:

    • utworzenie obiektu systemowego
    • [2.]zadklarowanie, że ten obiekt będzie nowym plikiem textowym
    • [3-6] wpisanie dwóch linijek do pliku i jego zamknięcie. Należy nie zapominac o zamykaniu otwartych plików, ponieważ mogą z tego wyniknąć niemiłe konsekwencje…

  9. Proste operacje na folderze

    +———— testFolder.vbs

    —–( źródło )—–

    opis:

    • stworzony zostaje obiekt systemowy, przypisanie iż obiekt ten jest folderem i wyświetlenie plików w katalogu

  10. Test funkcji getex oraz przynależność do grup

    +———— testGetEx_and_memberof.vbs

    —–( źródło )—–

    opis:

    • [1.] bind’owanie za pomocą providera LDAP do usera ‚s0352’ znajdującego się w OU studenci w domenie pjwstk.edu.pl .
    • [2.] aby pobierać zmienną typu ‚multivalue’ z AD należy skorzystać z funkcji ‚getEx’ zamiast standardowego ‚get’. zmienna memberList staje się tablicą o wartościach pobranych z atrybutu ‚memberOf’ obiektu ‚user’.
    • [5-9] pierwszy sposób wypisania grup, do których należy user. [6.] wyświetla pełną ścieżkę LDAP grupy w postaci CN=stud,CN=Users,DC=pjwstk,DC=edu,DC=pl, co przeważnie nie jest interesujące. Następnie bindujemy się do tej grupy i wyświetlamy jej atrybut ‚cn’ [common name] o który nam chodzi. Czyli raz bindowaliśmy się do usera pó�niej do grupy.
    • [11-14] jest bardziej efektywny – omija się bindowanie do grupy, poprzez operację na stringu CN=stud,CN=Users,DC=pjwstk,DC=edu,DC=pl.

  11. Skrypcik sprawdzający wygasanie [expirację] hasła

    +———— testPassNotExpir.vbs

    —–( źródło )—–

    opis:

    • dość ciekawe może wydać się to, co znajduje się w linijkach [4.] i [12.]. Jak widać obiekt ‚user’ ma atrybut zbiorczy flag ‚UserAccountControl’ [UserFlags dla WinNT]. Są w nim zapisywane np. takie rzeczy jak ‚hasło nie wygasa nigdy’, ‚konto jest zalock’owane’, ‚konto zablokowane’ i kilka innych. Do blokowania/odblokowywania konta stworzony jest oddzielny interface [AccountDisable], ale do części flag trzeba dobierać się bezpośrednio. Ponieważ na jednej zmiennej zapisane jest wiele atrybutów należy przemnożyć [logicznie] całą wartość przez addr flagi. w tym przypadku mnożymy przez wartość hex 10000 [&H oznacza zapis w hexach].
    • pozostałe wartości zmiennej UserAccountControl w MSDN’ie [search key:UserAccountControl];

  12. kiedy expiruje hasło

    +———— testPasswordExpirationLDAP.vbs

    —–( źródło )—–

    opis:

    • HA! oto wspaniały przykład na ‚jedną z tych dziwnych rzeczy’. Istnieje atrybut ‚PasswordExpirationDate’ zawierający… ha. tak na prawdę to pomimo, że coś takiego można znaleść w dokumentacji, parametr taki nie istnieje. Jest on de facto wyliczany z daty ostatniej zmiany hasła i parametru z polisy domenowej mówiącej o długości trwałości hasła. Całkiem logiczne. Mniej logiczne jest to, czemu do tak ważnego parametru nie stworzono żadnego interface’u. oj. przepraszam. Oczywiście, że istnieje. Dla providera WinNT załatwia się to w dwóch linijkach:

      set oUser=getobject("WinNT://pjwstk/s0352,user")
      wscript.echo oUser.PasswordExpirationDate

      Nie działa to jednak dla LDAP. Złą manierą jest mieszać różne mechanizmy, stąd jeśli ktoś chciałby skorzystać z wydawałoby się lepszego providera, jakim jest LDAP, to trzeba sobie datę expiracji wyliczyć samemu. Tak jak to widać powyżej. Słodkie, nieprawdaż?

    • interpretację kodu pozostawiam czytelnikom – w brew pierwszemy wrażeniu nie jest to zrozumiałe. Dla początkujących userów wyjaśnienie takiego szczegółu: znak ‚_’ to łamanie linii. Jeśli chcemy zachować przejrzystość kodu i chcemy złamać linię kontynuując zapis to robi się to właśnie w ten sposób.

  13. Trochę rejestru

    +———— testReg.vbs

    —–( źródło )—–

    opis:

    • W niniejszym skrypcie warto zwrócic uwagę na eleganckie rozwiązanie wyświetalnia błędów: utworzony zostaje obiekt standardowego wyjścia [3.] – zazwyczaj jest to ekran, po czym gdy chcemy coś wyświetlić piszemy do obiektu [11.]. Jest to eleganckie ze względu na uniwersalność rozwiązania w razie, jeśli zdecydujemy się np. że chcemy zapisywać wyniki do pliku. Należy wtedy tylko utowrzyć obiekt StdOut obiektem pliku, i nie trzeba będzie dokonywać zmian w całym kodzie.
    • w linijce [5.] wykorzystujemy WMI aby podłączyć się do rejestru komputera. Zmieniając kropkę w zapisie winmgmts:\.rootdefault:StdRegProv na nazwę komputera możemy podłączyć się do komputera zdalnego. Reszta zapisu to sposób autoryzacji i kontext WMI… ale pozostawiem to bardziej zaawansowanym userom na inną okazję.

  14. Mały psikus, otwierania aplikacji, wysyłanie znaków do aplikacji

    +———— testSendKeys.vbs

    —–( źródło )—–

    opis:

    • Oto prostu sposób na zrobienie komuś drobnego żarciku… no na systemach wintendo [w9x wME] z zainstalowanym WSH taka sztuczka skończy się bardzo, ale to bardzo nieprzyjemnie, więc proszę sobie zdawać z tego sprawę.
    • [1.] utworzenie obiektu ‚shell’
    • [2.] uruchomienie aplikacji – tutaj notepad. obiekt staje się relacją do aplikacji. Stąd wykonanie dalej wss.sendKeys spowoduje wysłanie znaków do tej aplikacji.
    • Resztę pozostawiam domyślności czytelnika.

  15. Jeszcze trochę WMI

    +———— testSysinfo.vbs

    —–( źródło )—–

    opis:

    • Jest to przykład bezkontextowego bindowania do WMI i wyświetlenie kilku podstawowych parametrów.
    • Więcej info o tym jakie jeszcze są parametry w MSDN’ie [search keyword: „WMI classes” koniecznie w cudzysłowiach]

  16. Operacja na plikach textowych tworzenie/dopisywanie

    +———— testTextFile.vbs

    —–( źródło )—–

    opis:

    • Troche lepszy sposób na operację na plikach textowych, z wykorzystaniem metod „CreateTextFile” i „OpenAsTextStream„, dzięki czemu można dobrze operować na strumieniach textowych.
    • skrypcik sprawdza czy plik istnieje [fso.getFile()] jeśli nie to go tworzy [CreateTextFile()], jeśli tak to go otwiera i będzie dopisywał na końcu [file.OpenAsTextStream(8,0)].