Windows Server 2008

Windows PowerShell: Filtr w lewo, Format w prawo Udostępnij na: Facebook

Autor: Don Jones

Opublikowano: 5 października 2009

Zawartość strony
Filtr w lewo  Filtr w lewo
Format w prawo  Format w prawo
Tajniki powłoki  Tajniki powłoki

 

Na liście pocztowej Windows PowerShell Most Valuable Professional (MVP) omawialiśmy ostatnio (i usiłowaliśmy udokumentować) „niespodzianki” Windows PowerShell, czyli takie mechanizmy, których działanie może stanowić zaskoczenie dla początkującego programisty powłoki i nastręczać pewnych trudności.

Dwie, najpoważniejsze niespodzianki wiążą się z filtrowaniem i formatowaniem. Jak wspomniałem podczas dyskusji, często zalecam programistom zapamiętanie reguły „Filtr w lewo, Format w prawo”, która pomaga w uniknięciu problemów związanych z tymi aspektami. Moim zdaniem ta ogólna zasada pozwala efektywniej wykorzystywać powłokę Windows PowerShell. A teraz przejdźmy do szczegółów

Filtr w lewo

Często wykorzystuję narzędzia cmdlet do zarządzania Active Directory, które są udostępniane nieodpłatnie przez firmę Quest (pod adresem quest.com/powershell) i zachęcam innych do ich stosowania. Jedno z poleceń cmdlet Get-QADUser zostało zaprojektowane z myślą o pobieraniu obiektów użytkowników z katalogu Active Directory. Zdarza mi się napotykać konstrukcje podobne do następującego polecenia:

Get-QADUser | Where-Object { $_.Department -eq "Sales" } | Set-QADUser -department "Inside Sales"

Powyższa instrukcja powoduje, że dla wszystkich użytkowników z Active Directory, których atrybut Department ma wartość „Sales”, wartość atrybutu zostaje zamieniona na „Inside Sales”. Problem pojawia się w momencie filtrowania danych. Pierwsze polecenie cmdlet Get-QADUser służy do pobrania wszystkich użytkowników z domeny.

Na szczęście domyślnie nie pobiera wszystkich atrybutów dla każdego użytkownika, ale w dużej domenie może narobić sporych szkód, ponieważ skazuje biedny kontroler domeny na przesyłanie informacji o kontach użytkowników na komputer kliencki. Komputer kliencki musi następnie przeanalizować każdego konto po kolei i pozbyć się tych obiektów, których atrybut Department nie zawiera wartości Sales. Co za marnotrawstwo!

I na tym właśnie polega efektywność zasady „Filtr po lewej". Zawsze warto przenosić kryterium filtrowania możliwie jak najbardziej w lewo w wierszu polecenia. W tym przypadku samo polecenie cmdlet Get-QADUser wspiera filtrowanie:

Get-QADUser -Department "Sales" | Set-QADUser -department "Inside Sales"

Polecenie cmdlet Where-Object nie jest już potrzebne. Co więcej dzięki zastosowaniu tej składni, polecenie Get-QADUser przekazuje polecenie filtrowania do kontrolera domeny, który pobiera i przesyła tylko te konta, które spełniają kryteria. Kontrolery domeny świetnie radzą sobie z filtrowaniem (w zasadzie to ich główna rola), a zatem umieszczamy proces filtrowania w najodpowiedniejszym miejscu, co przyspiesza jego realizację. Komputer kliencki nie będzie musiał przetwarzać tylu obiektów odbieranych z kontrolera domeny, dzięki czemu polecenie zostanie wykonane szybciej i bardziej efektywnie.

Oto kolejny przykład, tym razem wykorzystujący narzędzia Windows Management Instrumentation (WMI):

Get-WmiObject CIM_DataFile -computerName Server2 | Where { $_.FileName -like "*.dll" }

Polecenie to skontaktuje się z WMI na serwerze Server2, pobierze wszystkie wystąpienia klasy CIM_DataFile (reprezentującej pliki na twardym dysku) i odfiltruje te, które nie stanowią plików DLL. W ten sposób uzyskujemy listę plików DLL na danym serwerze. Jednak wykonanie tego procesu może zająć sporo czasu, ponieważ na komputer pobierane są informacje o wszystkich plikach znajdujących się na serwerze. Również w tym przypadku przeniesienie kryterium filtrowania w lewo okazuje się pomocne. Realizujemy je w następujący sposób:

Get-WmiObject CIM_DataFile -computerName Server2 -filter "FileName LIKE '*.dll'"

Trzeba użyć nieco innej składni filtra, ponieważ polecenie to nie jest wykonywane przez powłokę Windows PowerShell, lecz przesyłane do WMI na zdalnym komputerze. Wykonanie polecenia nadal chwilę potrwa, ale generować będzie mniej ruchu w sieci i w efekcie w mniejszym stopniu obciąża serwer Server2 oraz komputer kliencki. Warto wyrobić w sobie nawyk studiowania plików pomocy poleceń cmdlet (w tym przypadku Help Get-WmiObject) w celu sprawdzenia dostępnych opcji filtrowania. Instrukcję Where-Object należy stosować tylko wtedy, gdy wykorzystywane polecenie cmdlet Get-* nie wspiera potrzebnego sposobu filtrowania.

 Do początku strony Do początku strony

Format w prawo

Inny pułapka wiąże się z poleceniami cmdlet Format-*, takimi jak Format-Table oraz Format-List. Początkującym programistom zdarza się stosować następującą składnię:

Get-Process | Format-Table ID,VM,Name | Export-CSV c:\processes.csv

Powyższe polecenie nie zadziała. A dokładniej zostanie uruchomione, ale efekty nie będą zgodne z oczekiwaniami. Po dokładniejszym przestudiowaniu polecenia jego autorzy często sami dziwią się, co chcieli w ten sposób osiągnąć. Zbiór procesów ma zostać sformatowany do postaci tabeli, która następnie ma w jakiś sposób stać się plikiem .CSV? Jeśli chcemy uzyskać plik .CSV, który zawiera tylko pewne właściwości obiektów, należy uruchomić następujące polecenie:

Get-Process | Select-Object ID,VM,Name | Export-CSV c:\processes.csv

Jeśli efektem końcowym ma być sformatowana, kolumnowa tabela sprowadzona do postaci pliku tekstowego, należy uruchomić następujący kod:

Get-Process | Format-Table ID,VM,Name | Out-File c:\processes.txt

Jednak nie można łączyć ze sobą powyższych metod. Aby zrozumieć to ograniczenie, trzeba poznać pewne informacje dotyczące działania poleceń cmdlet Format oraz Out-*.

Potoki Windows PowerShell, w ramach których uruchamiane są polecenia, są zakodowane tak, aby kończyć się poleceniem cmdlet Out-Default. To polecenie cmdlet ogranicza się w zasadzie do przekierowania obiektów do polecenia Out-Host, które jest odpowiedzialne za wyświetlenie danych wynikowych na ekranie.

Wszystkie instrukcje w wierszu polecenia (czyli formalnie potoku), które nie kończą się poleceniem cmdlet Out-*, domyślnie zostają zakończone poleceniem Out-Default, które jest jednoznaczne z poleceniem Out-Host. Jednak polecenia cmdlet Out-* nie potrafią obsługiwać obiektów i potrzebują, aby zostały one przekształcone w instrukcje formatujące. A zatem gdy polecenie Out-Host otrzymuje obiekty Process, przesyła je do jednego z poleceń cmdlet Format-*. Wybór zastosowanego polecenia (Table, Wide, Custom czy List) zależy od zestawu warunków, których omówienie wykracza poza zakres tego artykułu. Wystarczy mieć świadomość, że obiekty zostają przesłane do jednego z poleceń cmdlet Format-*, które pobiera obiekty i generuje instrukcje formatujące. Polecenia cmdlet Out-* wspierają instrukcje formatujące i wykorzystują je do stworzenia odpowiedniego mechanizmu wyświetlania.

A zatem w praktyce istnieją trzy lub cztery główne polecenia cmdlet Out-*, które są najczęściej wykorzystywane: Out-Host, Out-File, Out-Printer oraz Out-String.

Zostały one zaprojektowane tak, aby akceptować jedynie instrukcje formatowania, a następnie przy ich pomocy konstruować dane odpowiednio wyświetlane na ekranie, zapisywane w pliku tekstowym, drukowane lub przesyłane do ciągu tekstowego. Aby utworzyć instrukcje formatujące, należy przetworzyć obiekty przy pomocy polecenia cmdlet Format-*. Polecenia cmdlet Format-* generują jedynie instrukcje formatujące. W związku z tym gdy uruchomimy kod:

Get-Process | Format-Table ID,VM,Name |Export-CSV c:\processes.csv

do pliku .CSV przesłane zostaną jedynie instrukcje formatujące wygenerowane przez polecenie Format-Table, co może wydawać się zaskakujące. Po wykonaniu polecenia cmdlet Format-* oryginalne obiekty zostają utracone i pozostają tylko instrukcje formatujące. Stąd kolejna prosta reguła: Format w prawo. Innymi słowy, należy umieszczać polecenie formatujące cmdlet po prawej stronie wiersza polecenia. Po poleceniu cmdlet Format-* może znajdować się jedynie znak końca linii lub polecenie cmdlet Out-*. W związku z tym następująca składnia jest prawidłowa:

Get-Process | Format-Table ID,VM,Name | Out-File c:\processes.txt

Polecenie Out-File wie, w jaki sposób odczytać instrukcje formatujące i wykorzystać je do stworzenia pliku tekstowego. Poniższa konstrukcja również jest dozwolona.

Get-Process | Format-Table ID,VM,Name

Bazuje ona na statycznie zakodowanym poleceniu Out-Default dokonującym przekierowania do polecenia Out-Host, które wie, jak wykorzystać instrukcje formatujące i wyświetlić dane w postaci tekstowej w konsoli lub oknie hosta. Ogólna zasada brzmi: formatowanie powinno znajdować się po prawej stronie polecenia, na samym końcu lub tuż przed poleceniem cmdlet Out-*.

I jeszcze jedna wskazówka: ponieważ polecenia cmdlet Out-* nie przekazują obiektów do potoku (poza jednym wyjątkiem), nie należy umieszczać po nich żadnych instrukcji.

 Do początku strony Do początku strony

Tajniki powłoki

Mam nadzieję, że niniejszy artykuł pomoże czytelnikom w zrozumieniu mechanizmu działania zaprezentowanych „niespodzianek”. Należy przynajmniej zapamiętać zasadę "Filtr w lewo, Format w prawo", która służy do zapobiegania potencjalnym problemom.

Po poznaniu sposobu działania powłoki łatwiej jest opanować małe dziwactwa charakterystyczne dla Windows PowerShell. Warto poświęcić czas na poznanie wewnętrznych mechanizmów, aby móc wykorzystać tę wiedzę, gdy powłoka zacznie zachowywać się w zaskakujący sposób. To najkrótsza droga do zostania guru Windows PowerShell.

O autorze

Don Jones należy do grona najbardziej doświadczonych szkoleniowców oraz autorów w dziedzinie Windows PowerShell. Co tydzień publikuje wskazówki Windows PowerShell na swoim blogu ConcentratedTech.com, za pośrednictwem tej witryny można skontaktować się z nim lub zadać mu pytanie.

 Do początku strony Do początku strony

Windows Server 2008