Centrum skryptów - Systemy operacyjne

Tworzenie samodokumentującego się skryptu Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

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.

Tworzenie samodokumentującego się skryptu

By opisać niewiarygodną głębię błękitu nieba nad Buenos Aires, trzeba by użyć specjalnych nazw kolorów. Błękit kobaltowy, morski, granat – żaden z nich nawet nie próbuje odmalować rzeczywistego odcienia kopuły przykrywającej stare miasto. Szerokie chodniki obramowane stuletnimi budynkami wyłożone są drobnymi płytkami. Siadłem na pustym metalowym krzesełku. Wonny powiew delikatnie przynosił zapachy cynamonu, kardamonu i tymianku. Mewy na rozpostartych skrzydłach surfowały po niebie w sposób, który wywołałby zazdrość samego Big Kahuna. Café con leche wydawała się niezwykle na miejscu i była dość mocna, by zwrócić na siebie uwagę mimo konkurencji obrazów i dźwięków miasta. Przybyłem tu, aby wygłosić wykład do grupy Microsoft Premier Customers na temat wykorzystania VBScript w celu uproszczenia zarządzania ich sieciami. Wydobyłem więc składaną mapę i zacząłem planować drogę z Calle Florida do Obelisk na Nueve de Julio Avenue.

Ustaliłem na mapie swoją pozycję. Jestem niedaleko centrum handlowego Gallerías Pacifico. Kilkukrotnie obracałem mapę, starając się zorientować ją względem położenia i otoczenia. W tym momencie wysoki, wytwornie wyglądający mężczyzna w ciemnym trzyczęściowym garniturze pojawił się obok i staną na drodze słońca. Jego cień, tańczący po mapie, sprawił, że uniosłem głowę. Wstałem, gdy powiedział – "Buenos días , señor".
"Buenos días" – odpowiedziałem z trudem.
"Ach, zapewne jest pan Amerykaninem?" – odpowiedział z lekkim brytyjskim akcentem.
Lekko zaskoczony, niepewnie potwierdziłem.
"Czy to pańska pierwsza wizyta w naszym pięknym mieście?" – zapytał.
Ponownie wydukałem tylko – Tak.
"Zatem mogę zaoferować panu moją pomoc. Czego pan szuka?" – zapytał uprzejmie.
Powiedziałem mu, po czym udzielił mi wyczerpujących wskazówek. Później jeszcze rozmawialiśmy kilka minut.

„To jest to!”, pomyślałem. „Samodokumentujące się miasto! Nie potrzeba tu map ani planów. Ludzie są tak przyjaźni, że rzadko znajdzie się dość czasu, aby odczytać mapę, zanim ktoś nie podejdzie, aby pomóc!”.

Wydarzyło się to kilka lat temu. Dziś, w moim domu w Północnej Karolinie, pogoda jest tak piękna, że przypomniała mi się ta podróż do Buenos Aires – i to, jak przyjemna może być funkcjonalność samodokumentowania. Możemy sprawić, aby nasze skrypty wykonywały dla nas podobne usługi, jeśli poświęcimy trochę czasu na wstępne planowanie. W tym artykule pokażemy, jak stworzyć skrypt pobierający komentarze z innych skryptów, które są zgodne z określonym wzorem. Wzory te można zmodyfikować, aby pasowały do naszych własnych potrzeb i rozszerzyć tę technikę poza samo tworzenie dokumentacji dla skryptów.

Przyjrzyjmy się skryptowi, w którym już umieszczono pewne informacje dokumentujące. W skrypcie GetSetIEStartPage.ps1, pokazanym na Rysunku 1 (który został napisany na potrzeby artykułu „How Can I Change My Internet Explorer Home Page?”), komentarze zostały umieszczone we wstawkach tekstowych, przypisanych następnie do zmiennej o nazwie $Comment. Wstawka tekstowa (ang. here-string) jest ograniczona tagami: początkowym złożonym ze znaku „at” i cudzysłowu (@" ) oraz końcowym  "@. Istnieją tu trzy bloki komentarza, które nas interesują. Pierwszy zawiera normalne informacje nagłówkowe: tytuł, autora, datę, słowa kluczowe oraz komentarz do samego skryptu. Drugi i trzeci blok dotyczą bezpośrednio głównych funkcji zawartych w tym skrypcie.

Rysunku 1 GetSetIEStartPage.ps1

Param([switch]$get,[switch]$set,$computer="localhost")

$Comment = @"

NAME: GetSetIEStartPage.ps1

AUTHOR: ed wilson, Microsoft

DATE: 1/5/2009



KEYWORDS: stdregprov, ie, [wmiclass] type accelerator,

Hey Scripting Guy

COMMENTS: This script uses the wmiclass type accelerator

and the stdregprov to get the ie start pages and to set the

ie start pages. Using ie 7 or better you can have multiple

start pages



"@ #end comment



Function Get-ieStartPage()

{

$Comment = @"

FUNCTION: Get-ieStartPage 

Is used to retrieve the current settings for Internet Explorer 7 and greater.

The value of $hkcu is set to a constant value from the SDK that points

to the Hkey_Current_User. Two methods are used to read

from the registry because the start page is single valued and

the second start pages key is multi-valued.



"@ #end comment

 $hkcu = 2147483649

 $key = "Software\Microsoft\Internet Explorer\Main"

 $property = "Start Page"

 $property2 = "Secondary Start Pages"

 $wmi = [wmiclass]"\\$computer\root\default:stdRegProv"

 ($wmi.GetStringValue($hkcu,$key,$property)).sValue

 ($wmi.GetMultiStringValue($hkcu,$key, $property2)).sValue

} #end Get-ieStartPage



Function Set-ieStartPage()

{

$Comment = @"

FUNCTION: Set-ieStartPage 

Allows you to configure one or more home pages for IE 7 and greater. 

The $aryValues and the $Value variables hold the various home pages.

Specify the complete URL ex: "http://www.ScriptingGuys.Com" make sure

to include the quotation marks around each URL. 



"@ #end comment

  $hkcu = 2147483649

  $key = "Software\Microsoft\Internet Explorer\Main"

  $property = "Start Page"

  $property2 = "Secondary Start Pages"

  $value = "https://www.microsoft.com/technet/scriptcenter/default.mspx"

  $aryValues = "https://social.technet.microsoft.com/Forums/en/ITCG/threads/",

  "https://www.microsoft.com/technet/scriptcenter/resources/qanda/all.mspx"

  $wmi = [wmiclass]"\\$computer\root\default:stdRegProv"

  $rtn = $wmi.SetStringValue($hkcu,$key,$property,$value)

  $rtn2 = $wmi.SetMultiStringValue($hkcu,$key,$property2,$aryValues)

  "Setting $property returned $($rtn.returnvalue)"

  "Setting $property2 returned $($rtn2.returnvalue)"

} #end Set-ieStartPage



# *** entry point to script 

if($get) {Get-ieStartpage}

if($set){Set-ieStartPage}

Aby przepisać komentarze z oryginalnego pliku do innego dokumentu, musimy otworzyć skrypt, wyszukać komentarze, po czym zapisać odpowiedni tekst do nowego pliku. Brzmi to prosto. Ach prawda, potrzebujemy jeszcze nazwy naszego nowego skryptu. Nazwijmy go GetCommentsFromScript.ps1.
Skrypt GetCommentsFromScript.ps1, pokazany na Rysunku 2, rozpoczyna się od wyrażenia Param, które pozwala nam przekazać informacje do skryptu podczas wykonywania. Oto wyrażenie Param:

Rysunku 2 GetCommentsFromScript.ps1

Param($Script= $(throw "The path to a script is required."))

Function Get-FileName($Script)

{

 $OutPutPath = [io.path]::GetTempPath()

 Join-Path -path $OutPutPath -child "$(Split-Path $script-leaf).txt"

} #end Get-FileName



Function Remove-OutPutFile($OutPutFile)

{

  if(Test-Path -path $OutPutFile) { Remove-    Item $OutPutFile | Out-Null }

} #end Remove-OutPutFile



Function Get-Comments($Script,$OutPutFile)

{

 Get-Content -path $Script |

 Foreach-Object `

  { 

    If($_ -match '^\$comment\s?=\s?@"')

     { 

      $beginComment = $True 

     } #end if match @"

   If($_ -match '"@')

     { 

      $beginComment = $False

     } #end if match "@

   If($beginComment -AND $_ -notmatch '@"') 

     {

      $_ | Out-File -FilePath $OutPutFile -append

     } # end if beginComment

  } #end Foreach

} #end Get-Comments



Function Get-OutPutFile($OutPutFile)

{

 Notepad $OutPutFile

} #end Get-OutPutFile



# *** Entry point to script ***

$OutPutFile = Get-FileName($script)

Remove-OutPutFile($OutPutFile)

Get-Comments -script $script -outputfile $OutPutFile

Get-OutPutFile($OutPutFile)vw

Param($Script= $(throw "The path to a script   is required."))

Korzyść wykorzystania parametru wiersza polecenia polega na tym, że nie musimy otwierać i modyfikować skryptu, aby przekazać doń ścieżkę źródłowego skryptu, z którego chcemy skopiować komentarze. Zapewniamy, że jest to parametr obowiązkowy, przypisując wartość domyślną zmiennej $Script. Wartość domyślna wykorzystuje polecenie throw do wywołania błędu, co oznacza, że skrypt zawsze spowoduje błąd, o ile zostanie wywołany bez wartości dla parametru–script.

Pozwolę sobie na małą dygresję, aby przyjrzeć się, jak polecenie throw jest wykorzystane w skrypcie the DemoThrow.ps1 pokazanym na Rysunku 3. Aby przejść poza błąd wywołany poleceniem throw w funkcji Set-Error, musimy najpierw ustawić wartość zmiennej $errorActionPreference na SilentlyContinue. Powstrzymuje to wyświetlenie komunikatu o błędzie i pozwala skryptowi kontynuować. Jest to równoważne ustawieniu On Error Resume Next w VBScript. Wyrażenie If służy do wyliczenia zmiennej $value. Jeśli warunek jest spełniony, natrafimy na wyrażenie throw i tworzony jest wyjątek. W celu określenia błędu wykorzystujemy funkcję Get-ErrorDetails. Pierwsze, co się dzieje, to wyświetlenie licznika błędów, który zostanie zwiększony o 1, jako że błąd został wywołany przez wyrażenie throw. Następnie pobieramy pierwszy błąd (błąd o indeksie równym 0 jest zawsze tym najświeższym) i przekazujemy obiekt błędu do polecenia cmdlet Format-List, wybierając wszystkie właściwości. Informacje o wywołaniu są jednak zwracane jako obiekt, zatem musimy bezpośrednio odwołać się do tego obiektu. Dokonujemy tego, odwołując się do obiektu wywołania przez właściwość InvocationInfo obiektu błędu. Wynikowe informacje o błędzie przedstawia Rysunek 4.

Rysunek 3 DemoThrow.ps1

Function Set-Error

{

 $errorActionPreference = "SilentlyContinue"

 "Before the throw statement: $($error.count) errors"

 $value = "bad"

 If ($value -eq "bad") 

   { throw "The value is bad" }

} #end Set-Error



Function Get-ErrorDetails

{

 "After the throw statement: $($error.count) errors"

 "Error details:"

 $error[0] | Format-List -Property * 

 "Invocation information:"

 $error[0].InvocationInfo

} #end Get-ErrorDetails



# *** Entry Point to Script

Set-Error



Get-ErrorDetails

Rysunek 4 Wykorzystanie wyrażenia throw do wywołania błędu

Powróćmy teraz do naszego głównego skryptu GetCommentsFromScript.ps1. Potrzebujemy funkcji, która utworzy nazwę pliku dla nowego dokumentu tekstowego, zawierającego wszystkie komentarze wydobyte ze skryptu. W tym celu użyjemy słowa kluczowego function i uzupełnimy je nazwą tej funkcji. Naszą funkcję nazwaliśmy Get-FileName, aby zachować zgodność z używaną w Windows PowerShell konwencją budowy nazw: czasownik-rzeczownik. Get-FileName będzie akceptowała pojedynczy parametr wejściowy – ścieżkę do skryptu, który ma zostać zanalizowany – i umieszczać go w zmiennej $Script wewnątrz funkcji. Oto początek funkcji Get-FileName:

Function Get-FileName($Script)

{

Następnie musimy uzyskać ścieżkę do tymczasowego folderu na komputerze lokalnym. Istnieje wiele sposób, aby to uzyskać, łącznie z mechanizmami środowiskowymi Windows PowerShell. Jednak zdecydowaliśmy się na użycie statycznej metody GetTempPath z klasy Io.Path .NET Framework. Metoda GetTempPath zwraca ścieżkę do folderu tymczasowego, czyli miejsca, w którym umieścimy nowo utworzony plik tekstowy. Ścieżkę folderu tymczasowego przechowamy w zmiennej $OutPutPath, tak jak w przykładzie:

$OutPutPath = [io.path]::GetTempPath()

Postanowiliśmy nazywać nasz nowy plik tekstowy na podstawie nazwy skryptu. W tym celu musimy oddzielić nazwę skryptu od nazwy ścieżki do folderu, w którym jest przechowywany. Użyliśmy do tego cmdlet Split-Path. Parametr –leaf informuje cmdlet, aby zwrócił tylko samą nazwę skryptu (poziom liścia). Gdybyśmy chcieli uzyskać tylko ścieżkę do katalogu zawierającego skrypty, moglibyśmy użyć parametru –parent. Umieściliśmy polecenie Split-Path wewnątrz nawiasów, gdyż chcemy, aby operacja ta nastąpiła w pierwszej kolejności. Następnie dodaliśmy znak dolara przed nawiasami, aby utworzyć podwyrażenie, które wykona kod i zwróci nazwę skryptu. Można by wykorzystać use.ps1 jako rozszerzenie nazwy dla naszego pliku tekstowego, ale mogłoby to być mylące, gdyż jest to rozszerzenie typowe dla skryptów. Dlatego też po prostu dodaliśmy rozszerzenie.txt do otrzymanej nazwy pliku i umieściliśmy całość w cudzysłowie. Teraz możemy użyć cmdlet Join-Path, aby utworzyć pełną ścieżką dla pliku wynikowego. Nowa ścieżka składa się z tymczasowego folderu przechowywanego w zmiennej $OutPutPath oraz z nazwy pliku utworzonej przy użyciu Split-Path. Naturalnie, można było użyć funkcji manipulowania i przycinania łańcuchów w celu wygenerowania ścieżki nowego pliku, ale znacznie prostsze i bardziej niezawodne jest wykorzystanie Join-Path oraz Split-Path do wykonywania operacji tego typu. Gotowy kod wygląda następująco:

Join-Path -path $OutPutPath -child "$(Split-Path $script-leaf).txt"

} #end Get-FileName

Teraz musimy zdecydować, jak zamierzamy obsługiwać zduplikowane pliki. Możemy odwołać się do użytkownika, informując go, że istnieje już plik o danej nazwie, stosując taki kod jak ten:

$Response = Read-Host -Prompt "$OutPutFile already exists. Do you wish to delete it <y / n>?"

if($Response -eq "y")

    { Remove-Item $OutPutFile | Out-Null }

ELSE { "Exiting now." ; exit }

Możemy też zaimplementować pewien algorytm nazywania, który utworzy kopię istniejącego pliku, zmieniając jego rozszerzeni na.old. Jeśli wybierzemy ten wariant, kod będzie wyglądał podobnie do następującego:

if(Test-Path -path "$OutPutFile.old") { Remove-Item-Path "$OutPutFile.old" }

Rename-Item -path $OutPutFile -newname "$(Split-Path $OutPutFile -leaf).old"

Możemy wreszcie usunąć istniejący plik, co zastosowaliśmy w naszym przykładzie. Działanie, które chcemy wykonać, realizowane jest przez funkcję Remove-OutPutFile, utworzoną przy użyciu słowa kluczowego Function, podając nazwę funkcji. Wykorzystaliśmy zmienną $OutPutFile jako wejścia dla funkcji, jak widać poniżej:

Function Remove-OutPutFile($OutPutFile)

{

W celu sprawdzenia, czy plik istniej, użyliśmy cmdlet Test-Path, dostarczając łańcucha przechowywanego w zmiennej $OutPutFile jako parametr. Cmdlet Test-Path zwraca tylko wartości True albo False, zależnie od tego, czy plik został znaleziony. Oznacza to, że możemy użyć wyrażenia If do sprawdzenia istnienia pliku. Jeśli plik istnieje, wykonamy działanie zawarte w bloku skryptu. Jeśli nie, blok skryptu nie zostanie wykonany. Możemy zobaczyć tutaj, że pierwsze polecenie nie odnajduje pliku i zwracana False. W drugim poleceniu blok skryptowy nie jest wykonywany, gdyż pliku nie odnaleziono:

PS C:\> Test-Path c:\missingfile.txt

False

PS C:\> if(Test-Path c:\missingfile.txt){"found file"}

PS C:\>

Wyrażenie If wewnątrz funkcji Remove-OutPutFile służy do sprawdzenia, czy plik wskazywany przez zmienną $OutPutFile już istnieje. Jeżeli tak, zostaje on usunięty przy użyciu cmdlet Remove-Item. Informacja zwrotna, która normalnie pojawia się po usunięciu pliku, przekierowywana jest do cmdlet Out-Null, zapewniając wykonanie bez zbędnych komunikatów. Kod ten pokazano poniżej:

if(Test-Path -path $OutPutFile) { Remove-Item $OutPutFile | Out-Null }

} #end Remove-OutPutFile

Po utworzeniu nazwy dla pliku wynikowego i usunięciu wcześniejszej wersji pliku wynikowego (o ile istniała) nadszedł czas na wydobycie komentarzy ze skryptu źródłowego. w tym celu utworzymy funkcję Get-Comments i przekażemy do niej zarówno zmienną $Script, jak i $OutPutFile, jak w przykładzie poniżej:

Function Get-Comments($Script,$OutPutFile)

{

Teraz możemy zacząć czytać tekst skryptu, używając cmdlet Get-Content, do której przekażemy ścieżkę do skryptu jako parametr. Polecenie cmdlet Get-Content odczytuje plik po jednym wierszu i przekazuje go do wyjścia polecenia (potoku). Gdybyśmy postanowili przechować wyniki w zmiennej, otrzymalibyśmy tablicę. Można następnie traktować ją jak każdą inną tablicę, a zatem uzyskać takie informacje jak odczytanie liczby elementów poprzez właściwość Length czy odwoływanie się bezpośrednio do poszczególnych elementów przez indeks, jak w poniższym przykładzie:

PS C:\fso> $a = Get-Content -Path C:\fso\  GetSetieStartPage.ps1

PS C:\fso> $a.Length

62

PS C:\fso> $a[32]

($wmi.GetMultiStringValue($hkcu,$key,   $property2)).sValue

Oto wiersz, który wykonuje odczyt pliku skryptu i przesyła wynik do potoku:

Get-Content -path $Script |

Teraz musimy zajrzeć do każdego wiersza w celu sprawdzenia, czy należy on do bloku komentarza. Aby zbadać każdy wiersz potoku wykorzystamy cmdlet ForEach-Object, który działa analogicznie do wyrażenia ForEach…Next pod tym względem, że pozwala na pracę z indywidualnymi obiektami pochodzącymi ze wskazanego zbioru, po jednym na raz. Znak słabego akcentu (`) sygnalizuje, że polecenie jest kontynuowane w kolejnym wierszu. Działanie, które będziemy chcieli wykonać względem każdego obiektu przychodzącego przez potok, zawarte jest w bloku skryptowym, ograniczonym parą nawiasów klamrowych. Tę część funkcji Get-Content pokazano poniżej:

ForEach-Object `

  {

Wewnątrz bloku procesu cmdlet ForEach-Object chcemy sprawdzić zawartość wiersza tekstu. W tym celu wykorzystamy wyrażenie If. Automatyczna zmienna $_ reprezentuje wiersz tekstu, który właśnie został przekazany przez potok. Operator –match pozwala na wykonanie porównania wyrażenia regularnego z otrzymanym tekstem. Operator –match zwraca wartość logiczną (True albo False) jako wynik. Wzór do porównania zaczyna się zaraz po operatorze –match, jak w przykładzie poniżej:

PS C:\fso> '$Comment = @"' -match '^\$comment\s?=\s?@"'

True

Wyrażenie regularne, którego użyliśmy w tym miejscu, zostało zbudowane przy użyciu kilku znaków specjalnych:

^ – powoduje dopasowywanie na początku wiersza
\ – znak ucieczki powodujący, że symbol $ jest traktowany jako literał, a nie jako znak specjalny używany w wyrażeniach regularnych
$comment – Znaki literalne
\s? – Zero lub więcej znaków odstępów (spacji, tabulatorów itp.)
= – znak literalny
\s? – Zero lub więcej znaków odstępu
@" – znaki literalne

Fragment kodu badający bieżący wiersz z potoku pokazano poniżej:

If($_ -match '^\$comment\s?=\s?@"')

Utworzymy teraz zmienną o nazwie $beginComment, służącą do oznakowania początku bloku komentarza. Jeśli zrobimy tak po spełnieniu wyrażenia –match, nastąpi to w momencie wykrycia początku bloku komentarza. Wartość tej zmiennej ustawimy na $True:

{ 

  $beginComment = $True

} #end if match @"

Teraz musimy sprawdzić, czy natrafiliśmy na koniec bloku komentarza. W tym celu ponownie użyjemy operatora –match, ale tym razem będziemy szukać sekwencji "@, zamykającej wstawkę tekstową. Jeśli ją znajdziemy, zmienimy wartość zmiennej $beginComment na False:

If($_ -match '"@')

     { 

      $beginComment = $False

     } #end if match "@

Utworzyliśmy zatem dwa wyrażenia If: pierwsze wykrywa początek wstawki tekstowej, a drugie jej koniec. Teraz chcemy przechwycić tekst, który zostanie zapisany w naszym pliku komentarzy. Jako warunek przyjmiemy prawdziwość (True) zmiennej. Dodatkowo chcielibyśmy, aby w wierszu tym nie występowała sekwencja „at” i cudzysłów (@"), gdyż oznacza ona koniec wstawki tekstowej. Aby móc to rozstrzygnąć, użyjemy złożonego wyrażenia If:

If($beginComment -AND $_ -notmatch '@"') 

     {

Teraz zapiszemy tekst do pliku wynikowego. Użyjemy do tego zmiennej automatycznej $_ zawierającej bieżący wiersz tekstu, kierując ją do cmdlet Out-File. Polecenie to otrzymuje również zmienną $OutPutFile, zawierającą ścieżkę do pliku wyjściowego. Użyjemy też parametru –append, aby określić, że kolejne wiersze mają być dopisywane do pliku. Gdybyśmy nie użyli tego parametru, plik tekstowy zawierałby tylko ostatni wiersz komentarzy, gdyż domyślnie cmdlet Out-File powoduje zastąpienie zawartości pliku docelowego. W moim przekonaniu najlepszym rozwiązaniem jest dodawanie komentarza po każdym zamykającym nawiasie klamrowym, aby wyjaśnić przeznaczenie tego bloku skryptowego. Sprawia to, że skrypt jest łatwiejszy do odczytania i upraszcza rozwiązywanie problemów lub modyfikacje:

$_ | Out-File -FilePath $OutPutFile -append

     } # end if beginComment

  } #end ForEach

} #end Get-Comments

Teraz utworzymy funkcję o nazwie Get-OutPutFile, która otworzy plik wynikowy do odczytu. Odszukanie folderu tymczasowego nie jest zbyt proste, ale za to dysponujemy już ścieżką do pliku w zmiennej $OutPutFile, zatem wygodniejsze jest użycie skryptu do otwarcia tego pliku. Funkcja Get-OutPutFile odbiera pojedynczą zmienną wejściową $OutPutFile, zawierającą ścieżkę do pliku, który chcemy otworzyć. Przy wywoływaniu funkcji Get-OutPutFile prześlemy do niej zmienną $OutPutFile. Można oczywiście przesłać do funkcji Get-OutPutFile dowolną wartość. Można nawet podać jawny łańcuch znakowy (bez ograniczających cudzysłowów):

Function Get-OutPutFile($OutPutFile)

{

 Notepad $OutPutFile

} #end Get-OutPutFile



Get-OutPutFile -outputfile C:\fso\GetSetieStartPage.ps1

Mówiąc ogólnie, jeśli zamierzamy przechwycić coś, aby przekazać to do funkcji, dobrym pomysłem jest umieszczenie danych w zmiennej i użycie tej samej nazwy zmiennej zarówno wewnątrz, jak i na zewnątrz funkcji. Jest to zgodne z jedną z zasad ergonomii tworzenia skryptów: „Nie komplikujmy roboczej części skryptu”. W tym przypadku, gdy wywołujemy funkcję, wykonujemy „prawdziwą robotę”. Aby zmienić to w nowych skryptach, musimy zmienić konkretną wartość łańcucha. Dzięki umieszczeniu łańcucha w zmiennej możemy łatwo zmienić jej wartość. W istocie przygotowaliśmy się do podania wartości tej zmiennej w wierszu polecenia albo za pośrednictwem innej funkcji. Jeśli tylko jest się da, należy unikać umieszczania literalnych wartości łańcuchów bezpośrednio w kodzie skryptu. W podanym niżej przykładzie kodu wykorzystujemy zmienną do przechowania ścieżki do pliku, która zostanie przesłana do funkcji Get-OutPutFile:

Function Get-OutPutFile($OutPutFile)

{

 Notepad $OutPutFile

} #end Get-OutPutFile



$OutPutFile = "C:\fso\GetSetieStartPage.ps1"

Get-OutPutFile -outputfile $OutPutFile

Kompletną funkcję Get-OutPutFile pokazano poniżej: Zamiast wpisywania literalnego łańcucha jako ścieżki do pliku wynikowego zmienna $OutPutFile otrzymuje wartość ścieżki utworzoną przez funkcję Get-FileName. Ta funkcja z kolei odbiera ścieżkę do skryptu zawierającego komentarze, które chcemy wydobyć. Tę wartość przekazujemy do skryptu jako parametr wiersza polecenia. Gdy funkcja ma tylko pojedynczy parametr wejściowy, można przekazać go do niej za pomocą pary nawiasów. Jeśli jednak używa ona dwóch lub więcej parametrów wejściowych, musimy użyć składni –parameter nazwa:

$OutPutFile = Get-FileName($script)

Teraz wywołamy funkcję Remove-OutPutFile (omówioną wcześniej) i przekażemy do niej ścieżkę do pliku wynikowego, zawartą w zmiennej $OutPutFile:

Remove-OutPutFile($OutPutFile)

Po ustaleniu nazwy pliku wynikowego możemy wywołać funkcję Get-Comments do odczytania komentarzy z pliku skryptu wskazywanego przez zmienną $script. Komentarze te zostaną zapisane w pliku wskazywanym przez zmienną $OutPutFile. Ten wiersz kodu wygląda następująco:

Get-Comments -script $script -outputfile $OutPutFile

Gdy wszystkie komentarze zostaną zapisane do pliku, wywołujemy funkcję Get-OutPutFile, przekazując do niej ścieżkę zawartą w zmiennej $OutPutFile. Jeśli nie chcemy, żeby plik komentarzy był automatycznie otwierany, możemy wykomentować ten wiersz z naszego skryptu albo wręcz usunąć go wraz z funkcją Get-OutPutFile. Jeśli jednak chcemy przejrzeć każdy plik przed jego zapisaniem, pozostawmy ten wiersz kodu na miejscu:

Get-OutPutFile($OutPutFile)

Wykonanie skryptu GetCommentsFromScript.ps1 ni powoduje wyświetlania żadnych komunikatów. Jedynym potwierdzeniem działania pliku jest pojawienie się nowo utworzonego pliku wyświetlanego w programie Notepad, jak pokazano na Rysunku 5.

Rysunek 5 Nowy plik tekstowy wyświetlany w Notatniku

Skrypt GetCommentsFromScript.ps1 można łatwo zaadaptować do własnych metod komentowania skryptów, a także do wydobywania innych informacji z plików tekstowych (na przykład z dzienników). Wszystko, co trzeba w tym celu zrobić, to modyfikacja wzoru wyrażenia regularnego oznaczającego początki i końce fragmentów tekstu, które chcemy wydobyć. Mamy nadzieję, że skrypt ten przyda się Wam w pracy. I oczywiście zapraszamy do witryny Skrypciarzy, w której co tydzień publikujemy nowy artykuł.

Ed Wilson i Craig Liebendorfer, Skrypciarze

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne