Weź, przetwórz, sformatuj.
Jedna z pierwszych rzeczy, do których musimy się przyzwyczaić rozpoczynając pracę z PowerShellem jest model układanki. Rzadko kiedy pisząc jakąś komendę ograniczymy się do jednego puzzla. Bardzo często pierwsza komenda, choć wyświetli ‘coś’, to nie wyświetli tego, czego nam potrzeba. Prosty przykład to komenda Get-ChildItem (dir/ ls). W innych wierszach poleceń na ogół możemy osiągnąć pożądany rezultat bez dodatkowych komend filtrujących, przetwarzających wyjście, czy wreszcie wyjście to formatujących. Najprostszy przykład to potrzeba wyświetlenia tylko folderów. W cmd.exe wpisalibyśmy po prostu dir /ad i już, foldery fruną w naszą stronę. PowerShell? Jeden element zwróci nam wszystko, drugi – przefiltruje:
dir | where { $_.PsIsContainer }
Format wyjściowy też różnie może być odbierany – a to za szczegółowy, a to za mało szczegółowy, a to brzydki po prostu (z taką opinią zetknąłem się wczoraj). Dobra wiadomość dla nas: zawsze możemy format wyjściowy zmienić. I jeszcze lepsza: niezależnie od tego jaką komendę chcemy ‘poprawić’ w tym względzie – to zawsze formatować będziemy tymi samymi narzędziami/ składnią. Inna sprawa, że nieco trzeba poćwiczyć, by dojść do wprawy. Ale podstawowe tricki są niezmienne. Załóżmy więc, że z widoku folderów kompletnie zbędne nam są informacje o ostatniej modyfikacji, tryb pliku, czy pusta zawsze długość, a dla odmiany chcielibyśmy liczbę plików i folderów w środku. Pozbycie się czegoś w zasadzie oznacza nie wybranie tego w naszej tabulce. Dodanie wymaga już nieco więcej zabawy, więc może zacznijmy od usunięcia (czyt. wybrania) tego, co nam trza:
dir | where { $_.PsIsContainer } | Format-Table Name
Dalej zaczynają się schody, czyli elementy słownikowe (hashtable). W przypadku komend formatujących element taki może zawierać informację o:
- tytule (label)
- wyrażeniu ‘generującym’ zawartość (expression)
- szerokości (width)
- równaniu (alignment)
Najbardziej interesujące jest wyrażenie, które pozwala nam ‘wyciągnąć’ z obiektu naprawdę wszystko, tak naprawdę może tam być skrypt, który łączy się z jakimś hostem używając WMI i wyciąga z niego dane, które w danej chwili są potrzebne. Na ogół oczywiście jest to po prostu sięgnięcie po jakieś metody/ właściwości obiektu, który wpada do rurki. W tym wypadku (liczby plików i folderów) przydadzą nam się metody GetFiles() i GetDirectories() obiektu, z którym będziemy pracować:
$FileCount = @{ Label = 'File(s)' Width = 20 Expression = { $_.GetFiles().Count } Alignment = 'Left' } $FolderCount = @{ Label = 'Folder(s)' Width = 10 Expression = { $_.GetDirectories().Count } Alignment = 'Center' } dir | where { $_.PsIsContainer } | Format-Table Name, $FileCount, $FolderCount
Zmienne $FileCount i $FolderCount to właście wspomniane elementy słownikowe. Jak widać napracowałem się nieco, by je rozpisać, ale to nie jest konieczne, obie definicje można skrócić używając po prostu pierwszych liter każdego z kluczy: l, w, e, a…:
$MyName = @{l='Name';e={$_.Name};a='center';w=30} dir | where { $_.PsIsContainer } | Format-Table $MyName, $FileCount, $FolderCount
Teraz mamy już pełną kontrolę nad szerokością, rozmieszczeniem, nazwą i zawartością poszczególnych kolumn. Jak widać wymagało to nieco pracy i wiedzy, ale plus jest taki, że ta wiedza może być używana wielokrotnie, formatowanie listy procesów, serwisów czy kluczy w rejestrze nie będzie się niczym w zasadzie różnić. Dla wielu będzie to wada (nie ma zbyt wielu pre-formatowanych wyników polecenia ls) dla innych zaleta (każde polecenie można sobie dowolnie sformatować). Jedna, myślę dość ważna uwaga: formatowanie zostawiajmy sobie na koniec. Obiekty, które z niego wychodzą, nie mają już nic wspólnego z oryginałem. Nie da się ich sortować, grupować czy filtrować. Można je tylko wypchnąć na zewnątrz: Out-Host, Out-File, Out-Printer, Out-Null 😉 I jeszcze jedno: PowerShell daje nam możliwość zapisania sobie tych formatek w pliku XML. Ale to już całkiem inna historia…