Minule jsem se v našem seriálu o programování elektroniky trošičku (a přátelsky) navezl do fanoušků Linuxu, když jsem si dovolil kacířský výrok, že práce v textovém prostředí Windows není vůbec špatná a v některých aspektech je možná dokonce i lepší než na Red Hatu, Debianu a dalších ikonách současného světa open-source.
Abych své tvrzení podpořil něčím hmatatelným, společně jsme si krok za krokem vysvětlili práci jednoduchého skriptu v PowerShellu, který se po spuštění spojil s webovým serverem České národní banky a zobrazil v textové podobě aktuální kurzy předem zvolených devízových měn.
Podívejte se na video dnešního experimentu v PowerShellu:
No dobrá, uznávám, že to byla opravdu jen základní ochutnávka a na Linuxu bych samozřejmě zvládnul úplně to samé, ovšem tím také skriptovací možnosti PowerShellu ani zdaleka nekončí. Ba právě naopak, můžete v něm totiž ovládnout a automatizovat kompletní Windows od A do Z.
Když někdo spustí PC, dorazí mi e-mail
A právě to si ukážeme v druhém experimentu, který bude fungovat tak trochu jako Velký bratr. Pomocí vestavěného Plánovače úloh totiž nastavíme pravidlo, aby systém pod naším účtem spustil speciální skript pokaždé, když se jakýkoliv jiný uživatel přihlásí k naší mašině v redakční kanceláři.

Na Gmail dorazila zpráva, že se mi někdo přihlásil k pracovnímu laptopu
Jakmile k tomu dojde, zhruba po minutě skript vygeneruje report s údaji o počítači, informací, kdo se nám to k němu právě přihlásil a vše skrze poštovní server odešle na můj Gmail.
Fiktivní Luboška Květáková
Za tímto účelem jsem na počítači vytvořil dalšího uživatele – Lubošku Květákovou. Bude představovat fiktivní a v kolektivu nepříliš oblíbenou kolegyni z kanceláře, která se kolegům v jejich nepřítomnosti ráda přihlašuje do jejich mašin a tropí v nich nezbednosti.

Kdykoliv se Luboška přihlásí k PC, dorazí mi e-mail s reportem
Do Květákové můžete projektovat své vlastní kolegy, rodinné příslušníky a vlastně kohokoliv, kdo by mohl mít práva k přihlášení na PC, ať už to bude osobní účet, anebo třeba nějaký společný a generický.
V každém případě, jakmile se Luboška přihlásí, do několika minut dorazí e-mail. Skript se spustí s mírným zpožděním, abychom měli jistotu, že se počítač třeba po studeném startu stačil přihlásit k síti, a nastavíme také jeho několikanásobné opakování, pokud první průběh selže. Redundance musí být!
Zkoušíme to v PowerShellu 7
Než se vrhneme na popis příkazů v PowerShellu krok za krokem, jen připomenu, že vše demonstruji v jeho nejnovější 7. generaci, zatímco na současných Windows včetně posledních Jedenáctek straší i nadále stárnoucí 5. generace pod názvem Windows PowerShell.
V příkazové řádce nejnovějšího PowerShellu bude přinejmenším korektně fungovat čeština v UTF-8 a obecně nemá smysl začínat se softwarem, který to má dříve či později tak jako tak spočítané.
Jako testovací platformu zároveň používám Windows 11, ve kterých mohu garantovat funkčnost příkladů. Přece jen máme rok 2022, a tak vše připravuji v aktuálních verzích produktů. Ze stejného důvodu nepoužívám prehistorické rozhraní příkazové řádky, ale PowerShell spouštím v moderním Windows Terminalu. Jako vývojové prostředí jsem zvolil Visual Studio Code a doplněk pro PowerShell, nicméně klidně si to celé napište v Poznámkovém bloku.
Zjištění času v PowerShellu
Hned na začátku se náš skript zeptá operačního systému, kolik je hodin. Budeme tedy vědět, kdy přesně došlo k jeho spuštění.
V PowerShellu k tomu slouží poměrně komplexní cmdlet Get-Date s hromadou voleb. Jednou z nich je parametr -Format pro nastavení textové podoby času:
Get-Date -Format "dddd dd.MM. yyyy HH:mm:ss"
Na první pohled asi rozpoznáte, které zástupné znaky formátu odpovídají kterým konkrétním hodnotám data a času, nicméně jejich kompletní výčet najdete zde.
Když příkaz výše zkopírujete do PowerShellu a stisknete ENTER, vypíše se čas a datum v podobě jako na obrázku. Takže třeba neděle 08.05. 2022 13:20:01.

Zjištění aktuálního času v PowerShellu
Jelikož chceme textovou hodnotu uložit do proměnné $cas pro pozdější použití, příkaz lehce upravíme:
$cas = Get-Date -Format "dddd dd.MM. yyyy HH:mm:ss"
Zjištění informací o PC v PowerShellu
V dalším kroku budeme potřebovat načíst popisné informace o počítači, abychom z e-mailu poznali, ke kterému se právě někdo přihlásil. Z PowerShellu můžeme přistupovat k systémovému API Windows hromadou způsobů, přičemž my zvolíme cmdlet Get-CimInstance.
Jedná se o API, které popisuje systém pomocí univerzálního datového modelu CIM (Common Information Model), a my se skrze něj můžeme ptát celé plejády systémových objektů.

Zjištění informací o základním hardwaru počítače
Jedním z těchto objektů je třída Win32_ComputerSystem, a když klepnete na odkaz s její dokumentací, uvidíte, že obsahuje desítky zajímavých údajů.
Jelikož nás zajímají jen některé, pomocí roury | (tu jsme si vysvětlili už minule) přesměrujeme výstup jednoho cmdletu do vstupu dalšího cmdletu Select-Object, pomocí kterého vybereme parametry, které nás zajímají.
My chceme z objektu vytáhnout hodnoty Manufacturer, Model, Name, PCSystemType a UserName, takže celý příkaz bude vypadat takto:
Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object Manufacturer, Model, Name, PCSystemType, UserName
Kdybych jej spustil ve svém PowerShellu, příkazová řádka zobrazí hezký formátovaný výstup:
Manufacturer: Dell Inc.
Model: Latitude 5320
Name: JAKUBSKANTB
PCSystemType: 2
UserName: JAKUBSKANTB\cizek
Hodnota 2 u položky PCSystemType odpovídá mobilnímu počítači; tedy tabletu, nebo laptopu.
V našem skriptu do terminálu nic vypisovat nechceme, a tak podobně jako v případě aktuálního času uložíme výsledek příkazu tentokrát do proměnné $pc:
$pc = Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object Manufacturer, Model, Name, PCSystemType, UserName
Zjištění informací o systému v PowerShellu
To bychom měli údaje o hardwaru, takže ještě operační systém. Postup bude stejný jako v předchozím kroku a jen s tím rozdílem, že se tentokrát zeptám třídy Win32_OperatingSystem, ze které vytáhnu položky LastBootUpTime, Manufacturer a Name:
Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object LastBootUpTime, Manufacturer, Name
Jaké další třídy bych mohl použít? Jsou jich desítky, týkají se prakticky všech aspektů operačního systému a najdete je na odkazech zmíněných výše.

Zjištění informací o systému a posledním studeném startu
V každém případě, my vybrané položky tentokrát uložíme do proměnné $os a LatBootUpTime v datovém typu datetime převedeme do textového řetězce ve stejném formátu jako aktuální čas:
$os = Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object LastBootUpTime, Manufacturer, Name
$casstartu = $os.LastBootUpTime.ToString("dddd dd.MM. yyyy HH:mm:ss")
Proměnná $casstartu nyní obsahuje datum a čas posledního studeného startu. Jelikož svůj laptop natvrdo vypínám jen zřídka a pouze jej usínám zaklopením víka, může se jednat o docela staré datum. Kdyby Luboška počítač restartovala, tímto způsobem se o tom dozvím.
Zjištění globálních proměnných v PowerShellu
Hromadu zajímavých popisných informací už za nás operační systém uložil do globálních proměnných, které jsou v PowerShellu dostupné pod hlavičkou env.
Kdybyste si je chtěli všechny vypsat do příkazové řádky, stačí v PowerShellu napsat příkaz:
ls env:
Nebo
dir env:
Výsledek bude vypadat nejspíše podobně jako na mém pracovním laptopu na obrázku níže.

Výpis globálních proměnných v PowerShellu
Ve výpisu mě zaujala třeba položka COMPUTERNAME, a tak ji použiji i pro naši zprávu, která dorazí do e-mailu. V powershellovém skriptu mohu k jednotlivým položkám env přistupovat tímto způsobem:
$env:COMPUTERNAME
Základní údaje tedy vytáhneme ze systému i bez potřeby o něco komplexnějšího dotazování skrze cmdlet Get-CimInstance.

Globální proměnné se jménem počítače, procesorovou architekturou, cestou k profilu uživatele a cestou k Windows
Není username jako username
Pozor, v globálních proměnných je i položka USERNAME, ta by nám ale byla k ničemu. Náš skript totiž budeme spouštět v kontextu konkrétního uživatele, ke kterému se budou vázat i globální proměnné.
Jelikož budu skript spouštět vždy v kontextu uživatele cizek (abych se gvůbec dostal ke skriptu, který bude uložený v mém zabezpečeném uživatelském adresáři), globální proměnná USERNAME bude také pokaždé obsahovat slovíčko cizek.

Uživatel v globální proměnné (env) stále odpovídá mně, protože skript spouštím ve svém vlastním uživatelském kontextu, ačkoliv s počítačem už pracuje Luboška Květáková
Skutečného uživatele, který právě teď pracuje s počítačem, třeba právě Lubošku Květákovou, jsem proto o dvě kapitol dříve vytáhli pomocí cmdletu Get-CimInstance a třídy Win32_ComputerSystem, která už pracuje v jejím kontextu.
Zjištění informací o síti v PowerShellu
Ve výčtu informací o PC nám chybí ještě síť. Stejně jako v předchozích případech bych se mohl pomocí Get-CimInstance dotázat některé ze systémových tříd Windows, které mají na starost konektivitu, nicméně abychom si v našem příkladu ukázali ještě něco dalšího, použiji speciální cmdlety přímo pro práci s LAN.

Výpis aktivních síťových adaptérů
Bude to ale velmi podobné. Do e-mailu bych rád vypsal seznam aktivních síťových adaptérů, o což se postará cmdlet Get-NetAdapter.
Nejprve z něj vytáhnu položky Name, InterfaceDescription, LinkSpeed a Status, ale ještě neskončím, výstup totiž skrze další rouru přesměruji do cmdletu Where-Object, kterým omezím finální výstup jen na ty adaptéry, jejichž položka Status odpovídá hodnotě Up. Jako operátor rovnosti v PowerShellu slouží příkaz -eq:
Get-NetAdapter | Select-Object Name, InterfaceDescription, LinkSpeed, Status | Where-Object Status -eq "Up"
To je krása, viďte? Pomocí cmdletů, které vracejí nějaká data, rour a cmdletů pro výběr a filtrování jsem v podstatě vytvořil dotaz, který se podobá jazyku SQL a příkazu SELECT něco WHERE něco.
V našem skriptu výsledek opět uložíme do proměnné $adaptery.
Další informace o síti v PowerShellu
To bychom měli síťové adaptéry a teď ještě sítové profily a konečně síťové konfigurace, ze kterých vytáhneme IP adresy. Pro jednoduchost ukázky pracuji jen se starými adresami ve formátu IPv4. K výpisu případných adres IPv6 by bylo třeba jen adekvátně přejmenovat hledané položky.

Informace o síťových profilech a konečně LAN IP adresách
Síťové profily získám pomocí cmdletu Get-NetConnectionProfile a nás v nich zajímají položky Name, InterfaceAlias a IPv4Connectivity:
Get-NetConnectionProfile | Select-Object Name, InterfaceAlias, IPv4Connectivity
Síťové konfigurace s IP adresami vytáhne cmdlet Get-NetIPConfiguration, přičemž nás budou zajímat položky InterfaceAlias a IPv4Address:
Get-NetIPConfiguration | Select-Object InterfaceAlias, IPv4Address
Profily uložím do proměnné $profily, konfigurace do $site.
Poštovní SMTP klient v PowerShellu
Skvělé, v proměnných máme uložené údaje o počítači, takže teď už to musíme jen všechno odeslat skrze e-mail na cílovou adresu.
O to se konečně postará powershellový cmdlet SMTP klientu Send-MailMessage. Pozor, už je zastaralý a Microsoft zatím nemá náhradu, takže při otevírání šifrovaného spojení s poštovním serverem pokaždé vyskočí varování, nicméně funguje, a pokud skrze něj nebudete posílat kódy k jaderným mezikontinentálním raketám Armády ČR, lze to zkousnout.

Odesíláme HTML e-mail s kódováním UTF-8 skrze SMTP server Googlu, pokud sami máte Gmail a přihlašovací údaje
Použiji svůj účet na Gmailu a SMTP server Googlu
PowerShell samotný vlastní SMTP server nenabízí, takže je třeba použít nějaký jiný. Jelikož budu odesílat zprávu na svůj Gmail, použiji SMTP server Googlu smtp.google.com na TCP portu 587 a s aktivním šifrováním SSL.
Google samozřejmě nabízí SMTP jen pro své uživatele, budu se tedy muset přihlásit vlastním účtem Gmailu, stejně jako bych se k pošťákovi přihlašoval z nějakého desktopového klientu.

Za pár sekund je už zpráva s přílohou na mém Gmailu
Přihlašovacím jménem je vaše e-mailová adresa, pokud ale používáte dvoufaktorovou autentizaci ke službám Googlu, u hesla to bude pochopitelně složitější. Namísto hlavního hesla si budete muset ve správě svého účtu na webu vygenerovat jednorázové heslo aplikací, které použijete i pro SMTP.



Jednorázové heslo aplikace vytvoříte na webu myaccount.google.com/security
Základní kostra pro odeslání e-mailu, jehož tělo bude ve formátu HTML, použije se kódování UTF-8 a zpráva bude obsahovat přílohu, může vypadat třeba takto:
$smtp = "smtp.gmail.com"
$port = 587
$login = "papousek@gmail.com"
$heslo = ConvertTo-SecureString "prihlasovaci heslo" -AsPlainText –Force
$odesilatel = "papousek@gmail.com"
$prijemce = "papousek@gmail.com"
$autentizace = New-Object System.Management.Automation.PSCredential($login, $heslo)
$kodovani = [System.Text.Encoding]::UTF8
$predmet = "Předmět e-mailu"
$telo = "<h1>Ahoj</h1><p>Nějaký text se zprávou</p>"
$priloha = "cesta k pripadne priloze, ktera se ma odeslat"
Send-MailMessage -From $odesilatel -To $prijemce -SmtpServer $smtp -BodyAsHtml -Body $telo -Subject $predmet -Attachments $priloha -Credential $autentizace -Port $port -UseSsl -Encoding $kodovani
Už máme skoro hotovo. V poslední kapitole nastavíme vestavěný Plánovač úloh ve Windows.
Spouštěj můj skript, kdykoliv se někdo přihlásí
Zatímco PowerShell 7 v novém Windows Terminalu je sexy a moderní, vestavěný Plánovač úloh je asi tak vkusný jako fialová kravata maturanta z roku 1993. Když jej spustíte, rázem se teleportujte o dvacet let zpět, je to totiž jeden z těch programů na Windows, který bude i za dalších 300 let vypadat stále stejně, ačkoliv my ostatní už budeme dávno připojení do nějakého toho matrixu.

Plánovač úloh ve Windows a naše úloha PoPrihlaseni
Aby toho nebylo málo, Plánovač úloh je nejen ošklivý, ale je to zároveň děsný a špatně naprogramovaný balast, takže občas na pár sekund přestane reagovat. A to i na posledních Windows 11. Je naprosto zjevné, že na jeho grafické rozhraní roky nikdo nesáhl, ačkoliv je to jinak jeden z nejmocnějších nástrojů v celém operačním systému.
Jak už jeho název napovídá, slouží k plánování operací, které nastanou v případě, že se splní nějaká podmínka. Spouští může být třeba nějaký exaktní časový okamžik – třeba pondělní ráno 7:35 –, ale stejně tak třeba každé páteční odpoledne.

Aktivátory naší úlohy budou všechny události, které mají něco společného s přihlášením uživatele. Úlohu trošku zdržíme, aby tou dobou už vše fungovalo
Spouští ale může být některá z mnoha a mnoha vnitřních systémových událostí, které by vás třeba ani nenapadly. Třeba instalace nového programu. Nás ale budou zajímat události související se startem, a tak je všechny označíme v dialogu nové úlohy.
Tím pádem Plánovač spustí náš skript nejen při studeném přihlášení (třeba po ostrém startu PC), ale i při pokusu o přihlášení skrze protokol vzdálené obrazovky, při přepínání mezi uživateli a tak podobně.

Akcí bude spuštění PowerShellu (pwsh) s naším skriptem
Pokud se tak stane, s mírným zpožděním provedeme akci Spustit program. Bude to příkaz pwsh – zkratka pro PowerShell 7 –, případně powershell, který nicméně spustí onu zastaralou a doposud předinstalovanou verzi PowerShell 5.
Příkaz pwsh spustíme s parametrem -File, který bude obsahovat absolutní cestu k našemu skriptu. V mém případě tedy třeba:
pwsh -File "C:\Users\cizek\OneDrive\Development\powershell\emajl.ps1"
Už zbývá nastavit jen jednu věc, ale tu zdaleka nejdůležitější. Jelikož je spouští přihlášení jakéhokoliv uživatele včetně Květákové, musíme zvolit uživatele, pod kterým systém náš skript vyvolá. Zároveň je třeba, aby měl patřičná práva. Zde automaticky předpokládám, že jste administrátory daného počítače.



PowerShell se spustí v kontextu jiného uživatele – mě. V nastavení úlohy také mohu zvolit, aby se při selhání několikrát zopakovala
Nastavím tedy svůj účet nehledě na to, jestli budu přihlášený a konečně potvrdím vytvoření nové úlohy. Plánovač si vše potvrdí žádostí o vyplnění přihlašovacího jména a hesla. Do těchto vod ještě autentizační vrstva Windows Hello nedorazila, otisky prstů, PIN apod. tedy použít nemůžete. Horko těžko jsem zjišťoval, jaké mám vlastně heslo, protože jej v praxi prakticky nemusím používat.
A to je vlastně vše. Jsme v cíli a už to všechno umíme stejně dobře jako zavazování tkaniček! Na posledním listu proto najdete už jen kompletní zdrojový kód powershellového skriptu, který přečtete levou zadní.
Kompletní zdrojový kód souboru emajl.ps1
Takže ještě jednou. Nejprve zjistíme aktuální čas, pak informace o PC, informace o operačním systému a informace o síti. Následně z těchto údajů poskládáme HTML kód zprávy. no a tu konečně odešleme pomocí SMTP serveru Gmailu. Musíme na něm mít účet.
Chcete-li použít jiný SMTP server, musíte znát jeho adresu, port, způsob šifrování a samozřejmě přihlašovací údaje.
# Zjištění aktuálního času v patřičném textovém formátu
$cas = Get-Date -Format "dddd dd.MM. yyyy HH:mm:ss"
# Zjištění informací o počítači a operačním systému pomocí API Common Information Model (CIM)
$pc = Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object Manufacturer, Model, Name, PCSystemType, UserName
$os = Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object LastBootUpTime, Manufacturer, Name
$casstartu = $os.LastBootUpTime.ToString("dddd dd.MM. yyyy HH:mm:ss")
# Rozklíčování čísleného kódu typu počítače
$typPocitace = $pc.PCSystemType
if($typPocitace -eq 0){ $typPocitace = "neznámý" }
if($typPocitace -eq 1){ $typPocitace = "desktop" }
if($typPocitace -eq 2){ $typPocitace = "laptop/tablet" }
if($typPocitace -eq 3){ $typPocitace = "desktop" }
if($typPocitace -eq 4){ $typPocitace = "server" }
if($typPocitace -eq 5){ $typPocitace = "server" }
if($typPocitace -eq 6){ $typPocitace = "spotřebič/IoT" }
if($typPocitace -eq 7){ $typPocitace = "superpočítač" }
if($typPocitace -eq 8){ $typPocitace = "centrální mozek lidstva" }
# Zjištění údajů o síťových adaptérech, profilech a konfiguracích/IP
$adaptery = Get-NetAdapter | Select-Object Name, InterfaceDescription, LinkSpeed, Status | Where-Object Status -eq "Up"
$profily = Get-NetConnectionProfile | Select-Object Name, InterfaceAlias, IPv4Connectivity
$site = Get-NetIPConfiguration | Select-Object InterfaceAlias, IPv4Address
# Vytvoření HTML s aktivními síťovými adaptéry
$html = "<h3>Aktivní síťové adaptéry:</h3><ul>"
foreach($adapter in $adaptery){
$html += "<li>$($adapter.Name) ($($adapter.InterfaceDescription)), linková rychlost $($adapter.LinkSpeed)</li>"
}
# Vytvoření HTML s aktivními síťovými profily (IPv4)
$html += "</ul><h3>Aktivní síťové profily:</h3><ul>"
foreach($profil in $profily){
$typ = $profil.IPv4Connectivity
if($profil.IPv4Connectivity -eq "LocalNetwork"){ $typ = "LAN"}
if($profil.IPv4Connectivity -eq "Internet"){$typ = "internetu"}
$html += "<li>$($profil.Name) ($($profil.InterfaceAlias)) připojeno do $typ</li>"
}
# Vytvoření HTML s IP adresami (IPv4)
$html += "</ul><h3>IPv4 adresy:</h3><ul>"
foreach ($sit in $site){
$html += "<li>$($sit.InterfaceAlias): $(-join($sit.IPv4Address))</li>"
}
# Kompletace HTML poštovní zprávy
$html = "
<h2>Haló, šéfe, nějaký loupežník se nám přihlásil k počítači!</h2>
<b>Čas události:</b> $cas<br>
<b>Přihlášený uživatel:</b> $($pc.UserName)<br>
<b>Počítač:</b> $($env:COMPUTERNAME), $($pc.Manufacturer) $($pc.Model) ($typPocitace)<br>
<b>Operační systém:</b> $($os.Manufacturer) $($os.Name.split("|")[0])<br><br>
<b>Čas posledního studeného startu PC:</b> $casstartu<br>" + $html
# Nastavení SMTP serveru pro GOOGLE
$smtp = "smtp.gmail.com"
$port = 587
$login = "uzivatel@gmail.com"
$heslo = ConvertTo-SecureString "heslo" -AsPlainText –Force
$odesilatel = "odesilatel@gmail.com"
$prijemce = "prijemce@gmail.com"
$autentizace = New-Object System.Management.Automation.PSCredential($login, $heslo)
$kodovani = [System.Text.Encoding]::UTF8
$predmet = "Spuštění počítače $env:COMPUTERNAME"
Send-MailMessage -From $odesilatel -To $prijemce -SmtpServer $smtp -BodyAsHtml -Body $html -Subject $predmet -Credential $autentizace -Port $port -UseSsl -Encoding $kodovani
Tento článek je součástí balíčku PREMIUM+
Odemkněte si exkluzivní obsah a videa bez reklam na devíti webech.
Vyzkoušet za 1 Kč
Nebo samostatné Živě Premium