Toto bude výsledek dnešní práce v PowerShellu. Tak hurá do toho

Toto bude výsledek dnešní práce v PowerShellu. Tak hurá do toho

Nainstaluj si PowerShell 7, žadoní po mně vestavěný PowerShell 5 ve WIndows 11

Nainstaluj si PowerShell 7, žadoní po mně vestavěný PowerShell 5 ve WIndows 11

V PowerShellu funguje jak dosovský dir, tak unixový ls

V PowerShellu funguje jak dosovský dir, tak unixový ls

Výpis podporovaných příkazů pomocí get-command

Výpis podporovaných příkazů pomocí get-command

Nápověda pomocí get-help

Nápověda pomocí get-help

Ale fuj, to je spuštěných Poznámkových bloků

Ale fuj, to je spuštěných Poznámkových bloků

Kill them all...

Kill them all...

Uložení surového výstupu do textového souboru

Uložení surového výstupu do textového souboru

Uložení formátovaného výstupu do HTML

Uložení formátovaného výstupu do HTML

PowerShell ISE a náš dnešní skript

PowerShell ISE a náš dnešní skript

Visual Studio Code s doplňkem PowerShell a náš dnešní skript

Visual Studio Code s doplňkem PowerShell a náš dnešní skript

Stažení kurzovního lístku pomocí cmdletu Invoke-WebRequest

Stažení kurzovního lístku pomocí cmdletu Invoke-WebRequest

A takhle bude celá sekvence vypadat v praxi

A takhle bude celá sekvence vypadat v praxi

Nyní už umíme rozlišovat jednotlivé řádky

Nyní už umíme rozlišovat jednotlivé řádky

Srozumitelnější rozpis jednotlivých kurzů. Pro jednoduchost příkladu jsme neošetřil první dva informativní řádky a závěrečné zalomení. To až později

Srozumitelnější rozpis jednotlivých kurzů. Pro jednoduchost příkladu jsme neošetřil první dva informativní řádky a závěrečné zalomení. To až později

Pokud nebude mít skript žádný argument, vynadáme uživateli a skript ukončíme

Pokud nebude mít skript žádný argument, vynadáme uživateli a skript ukončíme

Skript nelze v daném kontextu spustit

Skript nelze v daném kontextu spustit

Povolení spouštění všech skriptů aktuálního uživatele

Povolení spouštění všech skriptů aktuálního uživatele

Náš kurzovní dotazovač v PowerShellu, který se ptá webu ČNB

Náš kurzovní dotazovač v PowerShellu, který se ptá webu ČNB

Nainstaluj si PowerShell 7, žadoní po mně vestavěný PowerShell 5 ve WIndows 11
22
Fotogalerie

Hrajeme si v PowerShellu. Nandáme to Linuxákům a jejich dokonalým terminálům

  • Nejlepší příkazová řádka? Tu mají přece linuxové a unixové systémy
  • PowerShell od Microsoftu ale zvládne možná ještě lepší kousky
  • Dnes v něm ovládneme kurzovní lístek ČNB

Pro fanouška Linuxu je to denní chléb a jedna z nejpropracovanějších funkcí operačního systému. My na Windows na to už ale občas zapomínáme, máme totiž nějaký ten grafický program úplně na všechno. Řeč je samozřejmě o příkazové řádce.

Byť si pod ní mnozí představí zaprášenou minulost a nevkusný MS-DOS, bylo by to krajně nefér, ve skutečnosti je to totiž všechno naopak. Ostatně, nebýt příkazové řádky, svět, jak jej dnes známe, by vůbec nemohl existovat.

Bez nadsázky! Ta hezká okénka aplikací se stíny, všemožnými efekty a s vyhlazenou typografií jsou vlastně jen tou nejsvrchnější vrstvičkou počítačového UI. UI, které hraje klíčovou roli na mobilech a běžných desktopech, nicméně na serverech, superpočítačích a dalších specializovaných mašinách, které řídí svět, dodnes vládnou blikající kurzor a sofistikované textové aplikace.

Dnes ovládneme kurzovní lístek ČNB

Ačkoliv jsou tedy doby MS-DOSu ty tam, černá obrazovka právem straší i v těch nejnovějších Windows. Ovšem pozor, tím opravdu nemám na mysli morálně zastaralou příkazovou řádku cmd.exe, ale samozřejmě moderní textový interpret PowerShell, který v sobě skrývá stovky a stovky příkazů – tzv. cmdletů – a docela mocný skriptovací nástroj.

49e6798a-9916-4468-b23f-08cb07138dde
Toto bude výsledek dnešní práce v PowerShellu. Tak hurá do toho

A protože nedělní večery patří bastlení, zkusíme si dnes v PowerShellu napsat jednoduchý program na zjišťování ceny chorvatských kun i evropského eura podle aktuálního kurzovního lístku České národní banky. V úvodu si ale nejprve připomeneme samotnou práci v textovém prostředí na několika příkladech.

Nejsem žádná lama, teleportuj mě rovnou na povídání o skriptu, který se bude dotazovat ČNB na kurzy měn. Jasně, žádný problém, klikni sem.

Pokračování 2 / 8

Pětku, nebo naopak Sedmičku?

Jelikož je PowerShell integrální součástí všech novějších verzí Windows, naše kurzovní dotazovátko bude fungovat bez nutnosti instalace nějakého dalšího prostředí – třeba tolik oblíbeného interpretu jazyka Python.

Ovšem pozor, aby to bylo pro zelenáče co nejvíce frustrující, ve výchozím stavu se ve Windows nachází povážlivě stárnoucí pátá generace PowerShellu, ačkoliv Microsoft paralelně vyvíjí už 7. řadu tohoto interpretu a jazyka. Sedmička je k dispozici na GitHubu a k mání je nejen pro Windows, ale také pro mnohé linuxové systémy a samozřejmě i macOS.

b4e64544-a3c5-489f-9088-99df21bd0e4b
Nainstaluj si PowerShell 7, žadoní po mně vestavěný PowerShell 5 ve WIndows 11

Náš skript sice poběží v obou interpretech, jsou ale mezi nimi místy docela dramatické rozdíly, a tak by se měl zelenáč rozhodně pustit spíše do toho nejnovějšího. Je to vlastně obdobný rozkol jako v případě Pythonu 3 a jeho starší generace 2, která bohužel dodnes straší v mnoha webových návodech a rigidnějších linuxových distribucích, takže kdejaký začátečník jen nechápavě kroutí hlavou.

Špatně mi to zobrazuje češtinu!

Webu a linuxovým systémům dnes vládne kombinace Unicode/UTF-8, na Windows to ale bylo vždy krapet složitější. Pokud vám bude v PowerShellu náš skript v UTF-8 špatně zobrazovat české znaky, bude to pravděpodobně právě používáním starší 5. generace, která je součástí Windows, a proto se jmenuje Windows PowerShell.

e06cb305-c605-4055-bc07-e7a2ad2b69a9
Špatné kódování češtiny v předinstalovaném Windows PowerShellu (verze 5) a funkční Unicode/UTF-8 v PowerShellu 7. Všimněte si odlišných ikon programů 

V takovém případě by měla být nejjednodušším řešením instalace nového PowerShellu 7. Vřele také doporučují zahodit výchozí Příkazovou řádku (CMD/Windows Console Host) a nahradit ji moderním rozhraním Windows Terminal.

eb6287c1-7c56-475c-8bfc-04c7a6a4a3e15c000f9b-0b2a-45c4-ab39-7616a05422e5
Změna výchozího textového rozhraní na Windows Terminal a v něm spuštěný PowerShell 7 a náš skript s bezchybnou češtinou v UTF-8

V jeho konfiguraci pak stačí nastavit, aby se rozhraní Windows Terminal používalo ve výchozím stavu pro všechny textové programy, ať už je spustíte jakýmkoliv způsobem (třeba skrze dialog WIN+R). 

PowerShellem ovládnete celý počítač

PowerShell přináší uživateli ohromné množství komplexních příkazů – takzvaných cmdletů –, kterými můžete spravovat do nejmenšího detailu jak celý operační systém Windows, tak i další úlohy na počítači.

Aby byla práce s PowerShellem dostatečně univerzální, k mnoha tradičním příkazům ještě z dob zmíněného MS-DOSu nabízí přezdívky, které se naopak prosadily v linuxovém a obecně posixovém světě včetně macOS.

cc1eb2c1-204b-4a08-b6d7-d83751a22ae4
V PowerShellu funguje jak dosovský dir, tak unixový ls

Výpis obsahu aktuálního adresáře tedy provede jak dosový příkaz dir, tak univerzálnější ls. Textové okno zase smaže jak cls, tak unixové clear a v obou světech můžeme propojovat výstupy a vstupy programů skrze tzv. rouru |.

Pokračování 3 / 8

Get-command ukáže stovky příkazů

Základních příkazů, cmdletů a přezdívek v PowerShellu jsou stovky a je až s podivem, že na webu neexistuje nějaký oficiální a dostatečně přehledný adresář.

a0d0edb0-40b2-486f-8f2b-0f6729c3485a
Výpis podporovaných příkazů pomocí get-command

Ty základní najdete třeba zde, tady a všechny ostatní a nainstalované na vašem operačním systému odkryje editor powershellových skriptů ISE, nebo prostý příkaz:

get-command

Okénko se zaplní ohromným množstvím dostupných povelů, pro krokový výpis proto můžeme použít zmíněnou rouru |, kdy výstup přesměrujeme do dalšího programu more, jehož jediným účelem je výpis vždy jen do zaplnění obrazovky:

get-command | more

Get-help zobrazí nápovědu ke každému příkazu

Jak mám ale vědět, co který příkaz ve výpisu get-command dělá? Nu, stačí jeho název zkopírovat do Googlu, anebo použít cmdlet nápovědy get-help, který je komplexnější analogií unixového man.

8e8909a7-4107-4900-bcfe-dfcc301729f6
Nápověda pomocí get-help

Zaujal mě třeba program get-process. Jeho základní dokumentaci proto zobrazím zavoláním:

get-help get-process

A mám jasno, get-process vypíše tabulku s běžícími procesy. Každý z nich má své jméno a ID, pomocí kterého s ním mohu dále pracovat. Výpis ale mohu i jednoduše filtrovat.

Pokračování 4 / 8

Get-process je textový správce procesů

Takže kdybych chtěl získat seznam procesů, jejichž název odpovídá masce not*, stačí zadat:

get-process not*

Hvězdička na konci představuje libovolný pokračující text, a jelikož jsem před chvíli spustil Poznámkový blok, jehož proces se jmenuje Notepad, vypíše se mi v tabulce.

4e4b175b-9c19-4577-899e-a1a70ea70554
Ale fuj, to je spuštěných Poznámkových bloků

Z představy, že mi na počítači běží Poznámkový blok, jsem poněkud nervózní, a tak jej zabiju příbuzným příkazem:

stop-process čísloprocesu

Anebo klidně hromadně skrze masku s hvězdičkou:

stop-process -processname not*
839eb890-08b4-4714-8e42-eb5937dc8ca4
Kill them all...

Přesměrování výstupu do souboru

Textový výpis nemusí skončit jen v příkazové řádce, ale můžete jej uložit i do souboru pro další zpracování. Nejjednodušším způsobem jsou samozřejmě znaky pro přesměrování výstupu >>>.

76c6d87f-4016-45a6-8926-83efb12ba170
Uložení surového výstupu do textového souboru

Ten první výstup zapíše do nového souboru, takže kdybych potřeboval uložit seznam běžících procesů do procesy.txt, stačí zadat:

get-process > procesy.txt

Pokud znak použiji dvakrát:

get-process >> procesy.txt

Soubor se nepřepíše, ale výstup se zapíše na jeho konec, což se hodí pro případy, kdy třeba sledujeme vývoj nějaké proměnné a v souboru máme celou její historii pěkně po jednotlivých řádcích.

Pokračování 5 / 8

PowerShell umí uložit výstup do CSV i HTML

Primitivní přesměrování zvládne každé textové prostředí nejen na Windows, ale i na unixových systémech, PowerShell nicméně obsahuje i pár unikátních specialit pro formátovaný výstup.

c71dd9cb-3e15-4937-b925-ed5079777846
Uložení formátovaného výstupu do HTML

Třeba cmdlet export-csv, který dokáže tabelovaný výstup, který do něj přesměrujeme skrze rouru, uložit do CSV:

get-command | Export-Csv -Path prikazy.csv

A jelikož žijeme v době webové, PowerShell umí textový výstup převést dokonce i do HTML, který poté mohu opět přesměrovat do souboru:

get-command | ConvertTo-Html | Out-File prikazy.html

V čem programovat powershellové skripty

Fajn, takže to bychom měli demonstraci základní práce se samotným interpretem PowerShellu, teď už se ale pojďme podívat na jeho skriptování. Program napsaný v PowerShellu je běžný textový soubor s příponou ps1.

e4cb07c5-7cf8-4086-a811-0135870de862
PowerShell ISE a náš dnešní skript

Můžete tedy použít libovolný textový editor včetně Poznámkového bloku. Součástí Windows by ale mělo být i jednoduché vývojové prostředí PowerShell ISE. Sice má grafické rozhraní jak z přelomu století, nabízí ale přinejmenším našeptávač příkazů.

158fc7a6-41a6-4070-8881-3eef0767c83b
Visual Studio Code s doplňkem PowerShell a náš dnešní skript

Další možností je bezplatný editor Visual Studio Code, který má k dispozici doplněk pro programování v PowerShellu přímo od Microsoftu. Nabídne se sám k instalaci, jakmile v editoru otevřete libovolný soubor s příponou ps1.

Pokračování 6 / 8

Invoke-WebRequest je textový HTTP klient 

Základem našeho programu bude cmdlet Invoke-WebRequest, což je vlastně docela mocný textový HTTP klient, který se chová podobně jako třeba program curl na linuxových a unixových systémech.

781c7474-c89a-4946-8917-f80df0bad745
Stažení kurzovního lístku pomocí cmdletu Invoke-WebRequest

Pomocí tohoto příkazu stáhneme stručný kurzovní lístek v textovém formátu z webu České národní banky. Kdybychom to chtěli provést přímo v příkazové řádce PowerShellu, stačí zavolat příkaz:

Invoke-WebRequest https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt -OutFile kurzy.txt

Samotný název cmdletu je docela dlouhý, a tak můžeme použít i jeho zkratku – alias iwr:

iwr https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt -OutFile kurzy.txt

V obou případech se soubor uloží do aktuálního adresáře pod názvem kurzy.txt

Dekódujeme kurzovní lístek

Soubor je připravený pro strojové zpracování, každá z měn je totiž na různém řádku ve formátu:

země|měna|množství|kód|kurz

Takže záznam pro euro a páteční odpoledne vypadal takto:

EMU|euro|1|EUR|24,605

V našem skriptu zavoláme cmdlet podobným způsobem, nicméně jeho odpověď uložíme jako objekt do stejnojmenné proměnné. Proměnné v PowerShellu uvozuje znak $, takže příkaz bude vypadat takto:

$odpoved = Invoke-WebRequest https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt

Pokud vše proběhlo tak, jak mělo, v objektu $odpoved je nyní kompletní odpověď HTTP serveru včetně hlaviček, nás ale zajímá obsah odpovědi, a tak PowerShellu přikážeme, ať jej převede do prostého textového řetězce, který uložíme do další proměnné $text:

$text = $odpoved.Content.ToString()

Kompletní text bychom mohli vypsat do výstupu příkazové řádky třeba takto:

Write-Output $text
914b9764-9ba3-471d-b784-1f6beb82e346
A takhle bude celá sekvence vypadat v praxi

My si ale v dalším kroku dlouhý řetězec rozdělíme do pole po jednotlivých řádcích. Slouží k tomu metoda split, jejímž parametrem je dělící znak. Kurzovní lístek používá pro zalomení řádků standardní ASCII znak LF s číselným šestnáctkovým kódem 0x0A, a tak jej použijeme jako parametr:

$radky = $text.split(0x0A)

Jelikož nyní máme jednotlivé měny včetně úvodní hlavičky hezky uložené v poli, můžeme jej projít položku po položce. Slouží k tomu příkaz foreach:

foreach($radek in $radky){
    Write-Output "Řádek: $radek"
}

Úryvek výše projde pole a vypíše všechny řádky do standardního výstupu uvedené slovíčkem „Řádek:“ pro kontrolu, že se kompletní textový řetězec rozřezal tak, jak měl.

57278c5e-b58d-4339-a3ca-d08b78fc044f
Nyní už umíme rozlišovat jednotlivé řádky

Jak už jsme si řekli výše, takový řádek má podobu třeba:

EMU|euro|1|EUR|24,605

Každý z nich bychom tedy mohli dále rozřezat na jednotlivé dílky do pole, přičemž nožem tentokrát bude znak |:

$mena = $radek.split("|")

Namísto původního strojového řádku konečně vše vypíšeme mnohem přívětivějším způsobem:

foreach($radek in $radky){
    $mena = $radek.split("|")
    Write-Output "$($mena[2]) $($mena[1]) ($($mena[0])) stojí $($mena[4]) korun českých"
}

Všimněte si, že k jednotlivým dílkům pole přistupujeme stejně jako v ostatních programovacích jazycích skrze index v hranatých závorkách (index začíná vždy od nuly, nikoliv od jedničky) a při skládání hotového textového řetězce, který se jako celek vypíše do výstupu příkazové řádky PowerShellu, použijeme zápis ve formátu $($mena[2]). To je velmi důležité, jinak by se totiž do textu vložila celá proměnná $mena a za ní jako prostý text [2].

815f3422-0157-4f6b-8a6b-9ce9fa127e69
Srozumitelnější rozpis jednotlivých kurzů. Pro jednoduchost příkladu jsem neošetřil první dva informativní řádky a závěrečné zalomení. To až později

Pokračování 7 / 8

Skript vypíše jen ty kurzy, o které máme zájem

Tím by mohl náš program skončit, my jej ale přece jen ještě trošku vylepšíme. Skript se bude jmenovat kurzy.ps1 a namísto vypisování všech měn už v úvodu určíme, které nás zajímají uvedením kódu měny nebo jiného políčka v řádku.

Když nás tedy bude zajímat třeba euro, dolar a chorvatská kuna, spustíme skript z příkazové řádky takto:

.\kurzy.ps1 USD EUR kuna

Anebo třeba jen:

.\kurzy.ps1 koruna

Přičemž z kurzovního lístku ČNB se poté vyberou všechny koruny v nabídce: dánská, islandská, norská a švédská. To je chytré, viďte?

Čteme argumenty skriptu

Aby to tak mohlo fungovat, musíme se dostat k poli argumentů skriptu, které je uložené ve vestavěné proměnné $args. My se proto na začátku programu zeptáme, jestli toto pole obsahuje alespoň jednu položku, no a pokud ne, vypíšeme chybovou zprávu a příkazem Break skript ukončíme.

9b714005-b354-4ca4-b1ee-2d78244129bc
Pokud nebude mít skript žádný argument, vynadáme uživateli a skript ukončíme

V běžných programovacích jazycích bychom použili porovnávací operátor >= (větší, nebo rovno), v PowerShellu se ale používá trošku jiný zápis. Jako operátor >= zde slouží -ge (pod odkazem najdete i všechny ostatní).

Kontrola na počet argumentů skriptu by tedy mohla vypadat třeba takto:

if($args.length -ge 1){
    Write-Output "Vypisuji kurzy podle ČNB"
    Write-Output "------------------------"
}
else{
    Write-Output "Ale ne, musíš zadat kódy hledaných měn!"
    Break
}

V závěrečné smyčce našeho programu pak už jen projdeme opět pomocí foreach pole s argumenty a dalším operátorem -contains zjistíme, jestli se nevyskytuje v některém z dílku pole $mena, které právě analyzujeme. A pokud tomu tak bude, kurz měny opět hezky rozepíšeme do standardního výstupu – v tomto kontextu do příkazové řádky.

Celý skript v PowerShellu od hlavy až k patě vypadá takto:

if($args.length -ge 1){
    Write-Output "Vypisuji kurzy podle ČNB"
    Write-Output "------------------------"
}
else{
    Write-Output "Ale ne, musíš zadat kódy hledaných měn!"
    Break
}

$odpoved = Invoke-WebRequest https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt
$text = $odpoved.Content.ToString()
$radky = $text.split(0x0A)

foreach($radek in $radky){
    $mena = $radek.split("|")
    foreach($kod in $args){
        if($mena -contains $kod){
            Write-Output "$($mena[2]) $($mena[1]) ($($mena[0])) stojí $($mena[4]) korun českých"
        }
    }
}

Pokračování 8 / 8

Ale ne, PowerShell nechce spustit náš skript

Když nyní skript spustíte ve svém PowerShellu ve Windows Terminalu, dost možná se zobrazí rudé chybové hlášení s tím, že skript není důvěryhodný, a tak jej interpret odmítl spustit. PowerShell je v tomto směru velmi přísný.

7a951f0b-2f76-4d75-80fa-ba9613f0066e
Skript nelze v daném kontextu spustit

Abychom si to co nejvíce usnadnili, aktuálnímu uživateli Windows (nám) dáme práva ke spuštění všech skriptů, což je pro účely experimentování prakticky nezbytné:

Set-ExecutionPolicy -Scope CurrentUser Unrestricted
02e20463-3488-491d-8689-ec230443cf38
Povolení spouštění všech skriptů aktuálního uživatele

Kdybyste později chtěli spouštění opět zakázat, respektive omezit jen na podepsané skripty, stačí analogicky zavolat:

Set-ExecutionPolicy -Scope CurrentUser AllSigned

Webový klient je pouze začátek

Dnes jsme si ukázali, že příkazová řádka na Windows opravdu není jen ten prehistorický cmd.exe, který neumí prakticky nic a je to jen připomínka dávných dob. PowerShell je naopak velmi mocný nástroj, který s operačním systémem provede téměř cokoliv.

0b83a2e5-3081-4eee-bf64-71e1f0fe56e6
Náš kurzovní dotazovač v PowerShellu, který se ptá webu ČNB

My jsme si dnes vyzkoušeli jen jeho cmdlet pro práci s HTTP klientem, někdy příště si ale v textové řádce na Windows vyzkoušíme i hromadné operace s obrázky, konvertování videa a další fígle, na které vůbec nepotřebujete nějaký těžkotonážní grafický program.

Určitě si přečtěte

Články odjinud