Centrum skryptów - Systemy operacyjne

Jak użyć danych odczytanych z pliku tekstowego jako parametrów w pliku wsadowym?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak użyć danych odczytanych z pliku tekstowego jako parametrów w pliku wsadowym?

Cześć, Skrypciarze! Chcę zautomatyzować bardzo żmudne zadanie związane z licencjonowaniem serwera. Muszę przejść pętlą przez plik tekstowy wiersz po wierszu, pobrać nazwę użytkownika, identyfikator licencji oraz numer zasobu, a następnie nadać te wartości plikowi wsadowemu. Jak to zrobić?

-- DM

Cześć, DM. Zanim zaczniemy, upewnijmy się tylko – dziś jest piątek 21 marca, prawda? To tylko dla upewnienia się, tak, żeby nie wypaść z czasu jak Billy Pilgrim.

Uwaga: Podróże w czasie fascynowały od zawsze. Ekspertem jest tu chyba nasz Skrypciarz Peter Costantini, ale nie mam się go jak zapytać o szczegóły, bo właśnie wrócił do lat trzydziestych w nadziei na przekonanie „wspaniałego” kucharza o pseudonimie „Chef Boyardee”, by ten nie zaśmiecał świata swoim Beefaroni. Weeble także o mały włos nie doprowadziłyby do niewynalezienia widelca…

Nie, nie wiemy dlaczego, dobre Beefaroni nie jest złe.

Jeżeli chodzi o mnie to najchętniej cofnąłbym się do naszej Skrypciarskiej Olimpiady podczas której miałem niesamowite szczęście i przyjemność przetestowania 10.500 skryptów. To dopiero była zabawa…

No dobra, nigdy więcej. Wystarczy jeden skrypt dziennie. Dziś na przykład na temat używania danych odczytanych z pliku tekstowego jako parametrów w pliku wsadowym:

Const ForReading = 1



Set objShell = CreateObject("Wscript.Shell")



Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Pattern = "\d{1,}"



Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)



Do Until objFile.AtEndOfStream

    strLine = objFile.ReadLine

    arrItems = Split(strLine, " ")

    strUserName = arrItems(0)

    strAsset = arrItems(1)



    strLicenseID = arrItems(5)

   

    Set colMatches = objRegEx.Execute(strLicenseID)  

    strLicense = colMatches(0).Value



    strCommand = "%compsec% /c C:\Scripts\Test.cmd " & strUserName & " " & strAsset & " " & strLicense

    objShell.Run strCommand, 1, True

Loop



objFile.Close

Zanim przejdziemy do opisania skryptu rzućcie okiem na przykładowy plik tekstowy, jaki przesłał nam DM:

Username1 asset1 asset1 (v24) (licserver/1000 1111), start Wed 3/19 8:50

Username2 asset2 asset2 (v24) (licserver/1000 1112), start Wed 3/19 8:55

Username3 asset3 asset3 (v24) (licserver/1000 1113), start Wed 3/19 8:59

DM musi z każdego wiersza pobrać trzy elementy, a mianowicie:

  • Nazwę użtkownika (w wierszu 1. to Username1).
  • Numer zasobu (asset1).
  • Numer licencji. Dla wiersza 1 będzie to 1111, czyli ostatni numer z ciągu (licserver/1000 1111).

Skąd wytrzasnąć taką informację? Jesteśmy tak samo ciekawi jak Wy. Czytajcie więc dalej, a może wpadniemy na to jakoś…

Zaczynamy od zdefiniowania stałej ForReading i ustawienia jej wartości na 1; stała ta będzie nam potrzebna w trakcie otwierania pliku tekstowego. Po zdefiniowaniu stałej tworzymy wystąpienie obiektu Wscript.Shell, będziemy go używać w celu wywołania aplikacji (w tym przypadku pliku wsadowego). Następnym krokiem będzie utworzenie obiektu VBScript.RegExp; dzięki niemu właśnie możemy używać wyrażeń regularnych w obrębie skryptu. Za chwilę omówimy trochę obszerniej zagadnienie wyrażeń regularnych, teraz wystarczy tylko nadmienić, ze ustawiamy wartość właściwości Pattern naszego obiektu za pomocą poniższego wiersza kodu:

objRegEx.Pattern = "\d{1,}"

Jeżeli nie jesteście specjalistami od wyrażeń regularnych, to powiemy tylko, że właściwość Pattern określa wartość docelową, której szukamy; w celu uzyskania bliższych informacji zajrzyjcie do odpowiedniego artykułu w TechNet Magazine (j.ang.). Używając standardowej składni wyrażeń regularnych zauważycie na pewno wartość \d – oznacza to, że poszukujemy jakiejś liczby. Jakiej? Jakiejś pomiedzy 0 a 9, każda jest dobra tak w sumie. Znak {1,} oznacza, że musimy odnaleźć przynajmniej jedną cyfrę, jeżeli mamy więcej niż jedną cyfrę następująca po sobie, to też super. Innymi słowy, składnia \d{1,} wyszuka wartość 1, wyszuka także wartość 32, 732829, oraz 3747347324932, itp., itd.

Uwaga: W pliku przykładowym nadesłanym przez DM, identyfikator licencji ma zawsze cztery cyfry, czy można więc określić podczas wyszukiwania, że poszukujemy numeru czterocyfrowego i tylko takiego numeru? Oczywiście, że tak. W takim przypadku użylibyśmy składni \d{4} (wyszukaj tylko cztery następujące po sobie cyfry). Nie jesteśmy jednak w stanie zagwarantować, że wszystkie identyfikatory licencji na świecie składają się z czterech cyfr, mogą istnieć przecież jeszcze takie o numerach 835 czy 67453. Metoda użyta w skrypcie jest więc uniwersalna.

Po skonfigurowaniu obiektu wyrażenie regularne tworzymy wystąpienie obiektu Scripting.FileSystemObject, a następnie za pomocą poniższego wiersza kodu otwieramy plik C:\Scripts\Test.txt do odczytu:

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)

Teraz zaczyna się zabawa.

Ustawiamy pętlę Do Until i przechodzi ona przez plik, aż do momentu kiedy jego właściwość AtEndOfStream przyjmie wartość True; oznacza to, że pętla zakończy swoje działanie w momencie, gdy przejdzie przez wszystkie wiersze pliku. Za pomocą poniższego wiersza kodu sczytuje ona pierwszy wiersz pliku tekstowego, po czym przechowuje go w zmiennej strLine:

strLine = objFile.ReadLine

Co to oznacza? Oznacza to, że po pierwszym przejściu pętli, strLine będzie równa:

Username1 asset1 asset1 (v24) (licserver/1000 1111), start Wed 3/19 8:50

Czy to już koniec? Już prawie. Musimy przecież wydobyć wszystkie interesujące nas informacje, czyli nazwę użytkownika, numer zasobu oraz identyfikator licencji. Funkcja Split VBScript-u rozdziela strLine na tablicę arrItems:

arrItems = Split(strLine, " ")

Podczas rozdzielania strLine w miejscu każdej spacji uzyskujemy tablicę, która zawiera następujące elementy:

Username1 

asset1 

asset1 

(v24) 

(licserver/1000 

1111), 

start 

Wed 

3/19 

8:50

Czy taka tablica przyda nam się do czegoś? Jasne, że tak. Musimy pobrać nazwę użytkownika? Proszę bardzo, jest to element 0 w tablicy. Poniższy wiersz kodu pobiera nazwę użytkownika (czyli 0 w tablicy) i przypisuje ją zmiennej strUserName:

strUserName = arrItems(0)

Następnie w ten sam sposób pobieramy numer zasobu (czyli 1 w tablicy) i przechowujemy go w zmiennej strAsset:

strAsset = arrItems(1)

Zostaje nam już tylko identyfikator licencji, czyli 5 (pamiętajcie, że pierwszy element w tablicy ma zawsze numer porządkowy 0). Wszystko pięknie, jest tylko jeden problem, element 5 w tablicy wygląda w sposób następujący:

1111),

Nie wygląda to za pięknie, nie ma się jednak czym przejmować. Istnieje kilka sposobów na pobranie identyfikatora licencji z tej wartości. Najlepszą i najprostszą metodą będzie tutaj skorzystanie z wyrażenia regularnego. Mając to na uwadze nadajemy wartość 5 elementu w tablicy zmiennej strLicenseID, a następnie, korzystając z metody Execute przeszukujemy tę wartość pod kątem następujących po sobie cyfr:

Set colMatches = objRegEx.Execute(strLicenseID)

Po przywołaniu metody Execute wszystkie wystąpienia wartości docelowej zostają przechowane w kolekcji o nazwie colMatches. Z uwagi na strukturę naszego pliku tekstowego wiemy, że będzie tylko jedno wystąpienie wartości docelowej, dlatego też możemy pobrać identyfikator licencji (1111) poprzez pobranie wartości elementu 0 w kolekcji:

strLicense = colMatches(0).Value

Teraz mamy już wszystkie interesujące nas informacje, możemy więc wywołać nasz plik wsadowy. Musimy nadać mu trzy parametry wiersza polecenia:

C:\Scripts\Test.cmd Username1 asset1 1111

Nasze polecenie musimy wpisać w okno wiersza polecenia żeby uruchomić plik wsadowy. Takie polecenie można utworzyć za pomocą poniższego wiersza kodu:

strCommand = "%compsec% /c C:\Scripts\Test.cmd " & strUserName & " " & strAsset & " " & strLicense

Jak zapewne zauważyliście łączymy tu ścieżkę z plikiem wsadowym ze zmiennymi strUserName, strAsset, oraz strLicense, pamiętając o tym, aby po każdym parametrze umieścić spację. Na początku ciągu umieszczamy konstrukcję %comspec% /c. Po co? To po prostu instruuje skrypt, że chcemy uruchomić skrypt w nowym oknie konsoli (%comspec%) oraz że chcemy, aby okno zamknęło się w momencie zakończenia działania pliku wsadowego (/c). W zależności od tego jakie zadanie wykonuje plik wsadowy może okazać się to zbyteczne, okno może przecież zamknąć się samo. Pamiętajcie jednak: przezorny zawsze ubezpieczony.

Jaki będzie nasz wynik? Po pierwszym przejściu pętli zmienna strCommand będzie równa:

%compsec% /c C:\Scripts\Test.cmd Username1 asset1 1111

Po utworzeniu polecenia możemy wywołać plik wsadowy używając metody Run obiektu Shell:

objShell.Run strCommand, 1, Tru
Uwaga: Jeżeli zastanawiacie się do czego służy drugi parametr (1), to możemy wyjawić, że po prostu instruuje skrypt, aby uruchomił plik wsadowy w normalnym oknie. Trzeci parametr (True) instruuje skrypt, wstrzymał się z przejściem do następnego wiersza kodu, aż do momentu, kiedy plik wsadowy zakończy swoje działanie.

Następnie wracamy do góry pętli i powtarzamy proces dla kolejnego wiersza naszego pliku tekstowego. Po zakończeniu wszystkich działań przywołujemy metodę Close i zamykamy Test.txt.

Jeżeli zastanawiacie się jak poszło naszemu koledze Peterowi Costantini to zgooglujcie jeszcze raz Beefaroni. Chef Boyardee jest widocznie nieubłagalny, albo Peter Costantini mało przekonywujący. Można zawsze wrócić do momentu kiedy Chef Boyardee był jeszcze małym chłopcem i zagrozić mu jakoś. Albo i nie, bo jakiś głodny się zrobiłem…

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne