Scripting Games: moje notatki – 3

W chwili obecnej można już wrzucać skrypty w ramach czwartej konkurencji, czas więc najwyższy, by podsumować konkurencję nr 3. I znów miałem okazję nauczyć się od uczestników kilku nowych sztuczek. Choć nie ukrywam – jest też się czego przyczepić. Tym razem postanowiłem skupić się na konkretnych przykładach elementów, które można było napisać doskonale, ale można też było dokumentnie pogrzebać…

Ludzie to będą czytać!

Zacznę od tego, co niezmiennie mnie przygniata. Jest to szczególnie widoczne w kategorii początkujący, ale pojawia się (choć rzadziej) w kategorii zaawansowanych. Ja wiem, że Scripting Games to nie konkurs piękności, ale jeśli Wam się nie chce zadbać o prezentację, to od razu skrypt jawi się jako niechlujny i pisany “na złość”. Szczególnie upiorne są “jednolinijkowce”, na które postawiło wielu uczestników. I wierzcie mi, ja też je kocham. ALE: jednolinjkowiec w PowerShellu to nie seria poleceń rozdzielonych średnikami i zapisana w jednej linii – to jedna “rurka”, którą rozpisać można nawet w liniach 30-tu. Prościutki przykład: spróbujcie ogarnąć dwa fragmenty kodu:

$ComputerName = $env:COMPUTERNAME;$preContent = "<h2>Tu sobie napiszemy nasz naglowek</h2>"; $Date = Get-Date -Format "MM\/dd\/yyyy HH:mm:ss"; $postContent = "<hr>$Date"; $Title = 'Nasz tytul';Get-WmiObject -Class Win32_LogicalDisk -Filter DriveType=3 | select DeviceId, @{ n = 'Size(GB)'; e = { "{0:N2}" -f ($_.Size/1GB) }},@{ n = 'FreeSpace(MB)'; e = {"{0:N2}" -f ($_.FreeSpace/1MB) }} | ConvertTo-Html -PreContent $preContent -PostContent $postContent -Title $Title | Out-File (Join-Path ([environment]::GetFolderPath('MyDocuments')) ($ComputerName + '.html'))

Ciężko odczytać, prawda? A tak naprawdę, choć napisany w jednej koszmarnej linii – to nie jest to nawet “formalnie” jedna linijka. Spokojnie można to połamać:

Get-WmiObject -Class Win32_LogicalDisk -Filter DriveType=3 |             
    ConvertTo-Html -Property @{            
        Label = 'Drive'            
        Expression = {            
            $_.DeviceId            
        }            
            
    },@{             
        Label = 'Size(GB)'            
        Expression = {             
            "{0:N2}" -f ($_.Size/1GB)             
        }            
    },@{             
        Label = 'FreeSpace(MB)'            
        Expression = {            
            "{0:N2}" -f ($_.FreeSpace/1MB)             
        }            
    } -PreContent @'
    <h2>Tu sobie napiszemy nasz naglowek</h2>
'@ -PostContent @"
    <hr>
    $(Get-Date -Format 'MM\/dd\/yyyy HH:mm:ss')
"@ -Title 'Nasz tytul...' | Out-File -FilePath (            
        Join-Path -Path (            
            [environment]::GetFolderPath('MyDocuments')            
        ) -ChildPath "$ComputerName.html"            
    )

Moim zdaniem o wiele przejrzyściej. I, co zabawniejsze, to właśnie jest (technicznie rzecz biorąc) jedna rurka, czyli właśnie – jednolinijkowiec. I choć wielokrotnie o “złamałem” – to jednak nadal mógłbym wykonać go w jednej linii kodu. A łamałem jedynie po to, by inny człowiek mógł spokojnie przeanalizować mój kod. I, co też nie bez znaczenia, w prosty sposób go “odrobaczyć”. Najprościej bowiem ustawiać breakpointy na konkretnej linii. Średnio pomocne gdy nasz “skrypt” zapisany jest w jednej, jedynej linii… Puszczam oczko

Formatki na prawo, Filtry na lewo!

Tu sprawa jest o wiele prostsza, więc nie będę się jakoś strasznie rozpisywał. Po prostu – jeśli polecenie oferuje filtr i pozwala limitować wyniki u źródła to grzechem zaniedbania będzie z możliwości tej nie skorzystać. Grzech ten będzie mało kosztowny w przypadku opisywanym, ale w przypadku pewnych klas może sprawić, że nasze polecenie zwyczajnie nie zwróci wyników, albo na wyniki te będziemy czekać bardzo długo. WMI filtruje się stosunkowo prosto (szczególnie w takim wypadku, gdy interesują nas obiekty z wybraną wartością jednej z właściwości). Ciągnięcie po drucie informacji o wszystkich dyskach tylko po to, by zbędne po naszej stronie wyfiltrować przy pomocy Where-Object mija się z celem.

Łatanina

Tworzenie dokumentu HTML można rozwiązać na kilka sposobów. Jeden z nich to po prostu zebrać informacje, a następnie “posklejać” wszystko do kupy. I tu znów: PowerShell daje nam do tego konkretne narzędzie (here-string) dzięki któremu takie “sklejanie” jest bajecznie proste. A mimo to znalazły się osoby gotowe przepisywać ten sam tekst wielokrotnie, za każdym razem dodając jedno zdanie. Żebyż jeszcze użyli do tego StringBuildera… Ale nie, zwykle wyglądało to tak, że do $Dokument += “następną linię”. A na ogół wystarczyłby prosty here-string…

KonfertTu-Hateemel

Tworzenie kodu HTML w PowerShellu jest bardzo proste, mamy do tego cmdlet. To, czego nie wiedziałem wcześniej (a  czego użyłem powyżej) to możliwość budowania właściwości w ramach tego polecenia (bez pośredniego Select-Object). Ale to nie jedyna możliwość, którą on oferuje. Mamy możliwość tworzenia samej tabulki z danych (-Fragment), możemy przekazywać tablice ciągów znaków do większości parametrów (np. –PostContent ‘<hr>’,(Get-Date) ). Ale nie zabrakło osób, które uparły się cały dokument tworzyć na piechotę. Serio, począwszy od <html>, na </html> skończywszy. Nawet tabulkę “dłubały” owe osoby na piechotę. Zgroza… Rozczarowanie

Parametryzacja

Część osób naprawdę przemyślała parametry. Ba, nawet znalazł się odważny, który użył nowego dodatku w wersji trzeciej, [PSDefaultValue()]. Dodatek ten upiększa nam nieco pomoc do naszych poleceń, przykładowo, tworzymy funkcję:

function Get-HelpfulDefault {            
<#
    .Synopsis
    Only test help...
#>            
param (            
[PSDefaultValue(Help = 'Teraz')]            
[DateTime]$Start = (Get-Date),            
$End             
)            
    "Start: $Start End: $End"            
}            

A następnie pytamy PowerShella o pomoc dla parametru Start, który odpowiednio “ozdobiliśmy” i dowiadujemy się jaka jest domyślna jego wartość:

PowerShell-PSDefault-Help-Message

Nie zwala z nóg, to pewne – ale z pewnością przydać się może, szczególnie gdy wartość domyślną wyliczamy w sposób wybitnie zawiły. To jednak co szczególnie mnie urzekło, to przemyślane aliasy dla parametru pobierające wartość z rurki (nazwy komputera). Wszelkie __Server, Name, dzięki którym do tworzonego polecenia można przekazać bardzo rozmaite obiekty, bez konieczności ich uprzedniego przetworzenia. Z drugiej strony trafiały się parametry “z czapy”: Server(s), Target… Wreszcie, kilka skryptów w kategorii początkujących była “gotowa” do parametryzacji, a jednak autorzy z okazji nie skorzystali. Wyciągnęli zmienne parametry na początek kodu, ale zabrakło otoczki param… A było tak blisko. Puszczam oczko

I to w zasadzie wszystko – mam nadzieję, że w zadaniu czwartym nie będę już musiał patrzeć na niektóre z tych “potworków”. I znów nauczę się kilku nowych sztuczek. Uśmiech

~ - autor: Bartek Bielawski w dniu 17 Maj, 2013.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Połączenie z %s

 
%d blogerów lubi to: