Centrum Skryptów - Systemy Operacyjne

Jak uruchamiać i odbierać zadania oraz zarządzać nimi w programie Windows PowerShell 2.0?

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 uruchamiać i odbierać zadania oraz zarządzać nimi w programie Windows PowerShell 2.0?

Cześć, Skrypciarze! Zastanawiałem się nad napisaniem skryptu z użyciem klasy system.thread platformy .NET, umożliwiającego jednoczesne wykonywanie kilku czynności. Chcę przeprowadzić kwerendę usług domenowych usługi Active Directory, która będzie wymagać sporo czasu. Chciałbym, aby w czasie oczekiwania na zakończenie kwerendy skrypt wykonywał inne zadania. Stąd też pomysł użycia klasy system.thread. Jeśli zastosuję funkcję, kod będzie można bez większego trudu wykorzystać ponownie. Jak sądzicie? Czy to wykonalne? Czy zdarzyło się Wam kiedyś napisać taki skrypt?

-- FS

Cześć, FS! Czołem, tutaj skrypciarz Ed Wilson. Dziś rano popijam angielską czarną herbatę z laską cynamonu i słucham Marizy śpiewającej fado. W Charlotte jest chłodno i wilgotno, a kiedy zamknę oczy, nieomal czuję łagodną bryzę Morza Śródziemnego i czuję zapach ciastek pastel de nata. Kilka lat temu spędziłem miesiąc w Lizbonie, prowadząc warsztaty z programu Windows PowerShell. Wspominam ten czas znakomicie. Oto zdjęcie starej latarni, które zrobiłem jadąc nadmorską szosą z Luisem — moim przyjacielem i opiekunem w Portugalii.

W Lizbonie zresztą nauczyłem się dorzucać laskę cynamonu do herbaty. Portugalczycy rzecz jasna doprawiają w ten sposób kawę, ale odważyłem się kiedyś zrobić to z herbatą i wyszło znakomicie. Ciekawe, że w ciągu tygodnia kilkoro uczestników warsztatów przerzuciło się także na herbatę z laską cynamonu, stosując przejęty ode mnie trik, który ja wcześniej przejąłem od nich.

A przechodząc do Twojego pytania, FS: Nie zdarzyło mi się jeszcze napisać skryptu z użyciem klasy system.thread, ale zastanawiałem się nad tym. Nigdy się jednak do tego nie zabrałem, ponieważ w programie Windows PowerShell 2.0 wprowadzono pojęcie zadań. Przy użyciu zadania — czy to w konsoli programu Windows PowerShell, czy w skrypcie — można rozpocząć długotrwałą procedurę i natychmiast przejść do wykonywania innych działań.

Aby rozpocząć zadanie, należy najpierw włączyć usługi zdalne. Może to dziwne, ale program Windows PowerShell do uruchamiania zadań używa infrastruktury usług zdalnych. Aby włączyć usługi zdalne, należy użyć apletu polecenia Enable-PSRemoting. Należy pamiętać, że to polecenie należy uruchamiać z uprawnieniami administratora. Należy więc kliknąć prawym przyciskiem myszy ikonę programu Windows PowerShell i wybrać polecenie Uruchom jako administrator. Prawdopodobnie (zależy to od ustawień kontroli konta użytkownika) zostanie wyświetlony monit z pytaniem „Czy chcesz zezwolić następującemu programowi na wprowadzenie zmian na tym komputerze?”. Monit jest nieco mylący, ponieważ na razie nic jeszcze nie zrobiliśmy, więc program Windows PowerShell nie wprowadza żadnych zmian w systemie. Po uruchomieniu programu Windows PowerShell z uprawnieniami administratora należy użyć apletu polecenia Enable-PSRemoting do skonfigurowania programu Windows PowerShell w sposób umożliwiający korzystanie z usług zdalnych. Zostanie wyświetlony monit (chyba że zostanie użyty parametr –Force).

Uruchomienie apletu polecenia Enable-PSRemoting z parametrem –Force spowoduje, że program Windows PowerShell wyświetli takie dane wyjściowe, jak widać poniżej.

Po skonfigurowaniu usług zdalnych można rozpocząć nowe zadanie programu Windows PowerShell przy użyciu apletu polecenia Start-Job. Polecenie to jest uruchamiane jako zadanie umieszczane w bloku skryptu. Zadania otrzymują nazwy nadawane w sposób sekwencyjny: Job1, Job2 itd. Widać to poniżej:

PS C:\> Start-Job -ScriptBlock { get-process }



Id              Name            State      HasMoreData     Location             Command

--              ----            -----      -----------     --------             -------

1               Job1            Running    True            localhost             get-process





PS C:\>

Zadania otrzymują identyfikatory, które także mają nazwy nadawane sekwencyjnie. Pierwsze zadanie utworzone w konsoli programu Windows PowerShell ma zawsze identyfikator 1. W celu uzyskania informacji o zadaniu można używać jego indentyfikatora lub nazwy. Widać to poniżej:

PS C:\> Get-Job -Name job1



Id              Name            State      HasMoreData     Location             Command

--              ----            -----      -----------     --------             -------

1               Job1            Completed  True            localhost             get-process





PS C:\> Get-Job -Id 1



Id              Name            State      HasMoreData     Location             Command

--              ----            -----      -----------     --------             -------

1               Job1            Completed  True            localhost             get-process





PS C:\>

Po ukończeniu zadania można je odebrać. Aplet polecenia Receive-Job zwraca takie same informacje, co w przypadku, gdy zadanie nie zostanie użyte. Poniżej widać dane wyjściowe zadania Job1 (w formie skróconej, aby zaoszczędzić miejsce):

PS C:\> Receive-Job -Name job1



Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

-------  ------    -----      ----- -----   ------     -- -----------

     62       9     1672       6032    80     0.00   1408 apdproxy

    132       9     2316       5632    62            1364 atieclxx

    122       7     1716       4232    32             948 atiesrxx

    114       9    14664      15372    48            1492 audiodg

    556      62    53928       5368   616     3.17   3408 CCC

     58       8     2960       7068    70     0.19    928 conhost

     32       5     1468       3468    52     0.00   5068 conhost

    784      14     3284       5092    56             416 csrss

    529      27     2928      17260   145             496 csrss

    182      13     8184      11152    96     0.50   2956 DCPSysMgr

    135      11     2880       7552    56            2056 DCPSysMgrSvc

 ... (dane wyjściowe w formie skróconej)

Po odebraniu zadania dane znikają — chyba że zapiszemy je w zmiennej. Ilustruje to kod widoczny poniżej:

PS C:\> Receive-Job -Name job1

PS C:\>

Nieco zamieszania może wprowadzić fakt, że zadanie ciągle istnieje, a aplet polecenia Get-Job nadal pobiera informacje o nim. Widać to poniżej:

PS C:\> Get-Job -Name job1



Id              Name            State      HasMoreData     Location             Command

--              ----            -----      -----------     --------             -------

1               Job1            Completed  False           localhost             get-process





PS C:\>

Zalecałbym więc, aby po zakończeniu korzystania z obiektu job używać apletu polecenia Remove-Job do usunięcia pozostałości zakończonych zadań. Pozwoli to uniknąć zamieszania związanego z aktywnymi zadaniami, zakończonymi zadaniami i zadaniami oczekującymi na przetworzenie. Po usunięciu zadania próba pobrania informacji o nim przy użyciu apletu polecenia Get-Job zwraca błąd — zadanie już nie istnieje. Widać to poniżej:

PS C:\> Remove-Job -Name job1

PS C:\> Get-Job -Name job1

Get-Job : The command cannot find the job because the job1 name was not found. Verify the value of the Name parameter,

and then try the command again.

At line:1 char:8

+ Get-Job <<<<  -Name job1

    + CategoryInfo          : ObjectNotFound: (job1:String) [Get-Job], PSArgumentException

    + FullyQualifiedErrorId : JobWithSpecifiedNameNotFound,Microsoft.PowerShell.Commands.GetJobCommand



PS C:\>

Pracując z apletami poleceń związanymi z zadaniami, przeważnie nadaję zadaniom własne nazwy. Zadanie zwracające obiekty procesów przy użyciu apletu polecenia Get-Process może otrzymać np. nazwę getProc. Kontekstowe nadawanie nazw może być bardziej praktyczne od korzystania z takich nazw, jak Job1 czy Job2. Nie ma problemu, jeśli nazwy zadań są długie, ponieważ można ograniczyć potrzebę wpisywania, stosując symbole wieloznaczne. Odbierając zadanie należy pamiętać o przechowaniu zwróconych obiektów w zmiennej. Widać to poniżej:

PS C:\> Start-Job -Name getProc -ScriptBlock {get-process}



Id              Name            State      HasMoreData     Location             Command

--              ----            -----      -----------     --------             -------

3               getProc         Running    True            localhost            get-process





PS C:\> Get-Job -Name get*



Id              Name            State      HasMoreData     Location             Command

--              ----            -----      -----------     --------             -------

3               getProc         Completed  True            localhost            get-process





PS C:\> $procObj = Receive-Job -Name get*

PS C:\>

Mając zwrócony obiekt w zmiennej, można go używać z innymi apletami poleceń programu Windows PowerShell. Warto pamiętać, że obiekt jest rozszeregowany. Widać to poniżej — używam znaków gm jako aliasu apletu polecenia Get-Member:

PS C:\> $procObj | gm





   TypeName: Deserialized.System.Diagnostics.Process

Oznacza to, że nie wszystkie elementy członkowskie obiektu System.Diagnostics.Process platformy .NET są dostępne. Metody dostępne normalnie widać poniżej (gps to alias apletu polecenia Get-Process, gm to alias apletu polecenia Get-Member, a znaki –m wystarczają, aby jednoznacznie wskazać parametr –membertype w wierszu konsoli programu Windows PowerShell):

PS C:\> gps | gm -m method





   TypeName: System.Diagnostics.Process



Name                      MemberType Definition

----                      ---------- ----------

BeginErrorReadLine        Method     System.Void BeginErrorReadLine()

BeginOutputReadLine       Method     System.Void BeginOutputReadLine()

CancelErrorRead           Method     System.Void CancelErrorRead()

CancelOutputRead          Method     System.Void CancelOutputRead()

Close                     Method     System.Void Close()

CloseMainWindow           Method     bool CloseMainWindow()

CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)

Dispose                   Method     System.Void Dispose()

Equals                    Method     bool Equals(System.Object obj)

GetHashCode               Method     int GetHashCode()

GetLifetimeService        Method     System.Object GetLifetimeService()

GetType                   Method     type GetType()

InitializeLifetimeService Method     System.Object InitializeLifetimeService()

Kill                      Method     System.Void Kill()

Refresh                   Method     System.Void Refresh()

Start                     Method     bool Start()

ToString                  Method     string ToString()

WaitForExit               Method     bool WaitForExit(int milliseconds), System.Void WaitForExit()

WaitForInputIdle          Method     bool WaitForInputIdle(int milliseconds), bool WaitForInputIdle()

Poniżej widać metody obiektów rozszeregowanych; używam takiego samego polecenia, co poprzednio:

PS C:\> $procObj | gm -m method





   TypeName: Deserialized.System.Diagnostics.Process



Name     MemberType Definition

----     ---------- ----------

ToString Method     string ToString(), string ToString(string format, System.IFormatProvider formatProvider)





PS C:\>

Poniżej widać listę apletów polecenia, w których występuje fragment Job (tzn. powiązanych z zadaniami):

PS C:\> Get-Command -Noun job | select nameName----Get-JobReceive-JobRemove-JobStart-JobStop-JobWait-JobPS C:\>
PS C:\> Get-Command -Noun job | select name



Name

----

Get-Job

Receive-Job

Remove-Job

Start-Job

Stop-Job

Wait-Job





PS C:\>

Jak widać, omówiliśmy cztery spośród sześciu apletów poleceń. To już wszystkie podstawowe informacje o uruchamianiu i odbieraniu zadań oraz zarządzaniu nimi. Zapraszamy jutro na kolejny artykuł z serii poświęconej obsłudze zadań.

Jeśli chcecie szybciej dowiadywać się, jakim tematom poświęcone będą kolejne artykuły, śledźcie nas w serwisie Twitter lub Facebook. W razie jakichkolwiek pytań piszcie do nas na adres scripter@microsoft.com lub publikujcie na oficjalnym forum skrypciarzy. Do zobaczenia jutro.

Skrypciarze Ed Wilson i Craig Liebendorfer

 

 Do początku strony Do początku strony

Centrum Skryptów - Systemy Operacyjne