Paralelní spouštění úloh v Powershellu
Paralelní spouštění úloh v Powershellu
Powershell workflow - posíláme zprávu určitým uživatelům na všechny stroje, kde jsou přihlášení    

Tohle je první článek, který píšu od své nemoci v roce 2013. Sice jsem loni začal psát článek o tom, jak psychicky přežít léčbu rakoviny, ale pak jsem si řekl, že se na to vyprdnu. Nejsem doktor, jsem ajťák. O rakovině a její léčbě ať píše někdo jiný. Když nad tím tak zpětně přemýšlím, tak by mi leckdy bylo mnohem lépe, kdybych o tom nic nevěděl.

Takže o čem to bude. Bude to o powershellu a jedné jeho úžasné možnosti. Není to teda nějaký extra velký objev. Pokud je powershell váš denní chleba, tak to bude věc, kterou dobře znáte. Ale pokud jako já powershell spíš jen používáte na malé věci, leckdy opravujete scripty jiných bez hlubší znalosti fungování, tak tohle vám může ušetřit spoustu času. Bude to totiž o workflow a o možnosti, jak zajistit paralelní zpracování položek pole. Což je něco, co může urychlit běh vašeho scriptu z hodin na sekundy.

Na počátku byla myšlenka, jak by šlo udělat, abych mohl poslat zprávu na obrazovky členů nějaké skupiny v Active Directory, ale tak, aby se to zobrazilo na obrazovkách všech počítačů, kde jsou přihlášení, protože nevím, jestli jsou na svém PC, na nějakém serveru nebo jsou zrovna přihlášení u nějakého uživatele. Poslat zprávu z command promptu Windows není takový problém. Pokud chci poslat zprávu například uživateli franta na počítač FRANTA-PC, tak to bude vypadat takto:

msg franta /server:FRANTA-PC "Neflákej se a něco dělej!"

Pokud bych to chtěl poslat aktuálně přihlášenému uživateli na stroji FRANTA-PC, tak to bude vypadat takto:

msg * /server:FRANTA-PC "Neflákej se a něco dělej!"

Takže bych mohl teoreticky poslat zprávu pro uživatele franta na všechna PC ve firmě. To by ale nebylo moc elegantní. Byl by to takový spam. To ale nechceme, protože je to hnusné a protože bychom si nemohli ukázat, jak to jde udělat elegantně. Použijeme totiž kombinaci nástrojů powershellu, abychom to pěkně vyladili. Pomocí modulu pro AD management v powershellu vezmeme všechny PC v doméně, pak pomocí WMI budeme zjišťovat, kdo je na nich přihlášený, porovnáme to se členy skupiny, která ás zajímá. Zní to jednoduše a v principu to jednoduché je. Problém je pouze ve WMI a jeho rychlosti. Pokud bychom to dělali postupně, tak bude jednodušší najít si členy skupiny, jejich čísla v seznamu a zavolat jim. Ony jsou totiž WMI příkazy strašně pomalé. Tedy spíš je problém v tom, že pokud se něco nepovede, ta hrozně dlouho trvá, než WMI vrátí chybu a pokračuje. Takže s každým vypnutým počítačem by rostla doba, kterou by script běžel. Proto pošleme WMI dotaz na všechny počítače v síti paralelně. A k tomu použijeme něco, čemu se říká powershell workflow. Workflow je v powershellu určeno k dlouhotrvajícím běhům, opakovaným úkolům, často spouštěným úlohám, k paralelnímu běhu na jednom nebo více PC, k aktivitám, které může přerušit i restart a ony pak musí doběhnout. Funguje od powershellu verze 3.0. Tenhle článek nemá za cíl přesně vysvětlit logiku workflow. Ukáže jen jeden příklad použití. Pokud o workflow chcete vědět více, tak doporučuji tento článek:
https://blogs.technet.microsoft.com/heyscriptingguy/2012/12/26/powershell-workflows-the-basics/

Cíl známe. Potřebujeme najít, kde všude jsou přihlášení kolegové a poslat jim zprávu. Nejdřív si ukážeme workflow a pak si rozebereme jeho obsah:

workflow send-msg

{
param($group, [string[]] $message)

$members = get-adgroupmember -identity $group | select samaccountname
$computers = get-adcomputer -filter * -searchbase "OU=Computers,DC=tnx,DC=cz" | select name

foreach -parallel ($computer in $computers)
{
sequence {
$pc = $computer.name
$owner = Get-WmiObject -Class Win32_ComputerSystem -Property UserName -PSComputerName $pc
if ($owner -ne $null) {
$username = $owner.Username
foreach ($member in $members) {
$user = $member.samaccountname
$domainuser = "TNX\" + $user
if ($domainuser -eq $username) {
$recipient = "/server:" + $pc
msg $user $recipient $message
}
}
}
}
}
}

Když se na to podíváme, tak to vypadá velmi podobně jako funkce. Na začátku jsem si workflow pojmenoval. Jmenuje se send-msg. Tímto jménem pak budu workflow volat z powershellu stejně, jako se volá třeba funkce. Pak definuju parametry, které můžu do workflow poslat a vloží se do proměnných $group a $message. U $group nedávám typ, protože potřebuju, aby měl powershell možnost proměnou přetypovat, ale $message bude prostě string. Workflow pak budeme volat třeba takto:

send-msg –group bratrstvo_kocici_pracky –message "Dneska oběd U Skotačivého Králíčka!"

Takže pouštímě workflow, dostali jsme pomocí parametru jméno skupiny a zprávu. Jméno skupiny použijeme k tomu, abychom zjistili její členy.

$members = get-adgroupmember -identity $group | select samaccountname

Následně načteme jména počítačů z Active Directory. Hledání jsme omezili pomocí OU. Pokud to budete potřebovat pustit na celý strom, tak parametr -searchbase vynecháte. Abychom omezili objem dat, tak chceme pouze jméno.

$computers = get-adcomputer -filter * -searchbase "OU=Computers,DC=tnx,DC=cz" | select name

A teď přichází ta krása. Za normálních okolností bychom použili foreach a ten by bral jeden stroj po druhém, tedy jednoho člena pole po druhém, zkoumal, jestli na něm nejsou přihlášení členové skupiny a posílal zprávu. S každým vypnutým počítačem by se zpracování natahovalo. Jenže workflow umí něco, co se jmenuje foreach -parallel. V rámci tohoto cyklu můžeme použít příkaz sequence, který ohraničuje část kódu, který chceme pustit paralelně na všechny členy pole. Takže co tam máme zajímavého:

$owner = Get-WmiObject -Class Win32_ComputerSystem -Property UserName -PSComputerName $pc

Pomocí WMI dotazu se ptáme, kdo je přihlášený na počítači a ukládáme to do proměnné. (Pokud víte, že bude spousta PC vypnutých, tak nakonec přidejte parameter: -ErrorAction SilentlyContinue, abyste se vyhnuli červenému moři na obrazovce.) Pokud není výsledek prázdný, tak porovnáváme s členy skupiny a hledáme shodu. Dělají se tam kosmetické úpravy, protože ti uživatelé jsou v různých formátech. Aby to šlo porovnat, tak musí být oba ve stejném formátu, takže je převádím na formát doména\uživatel. Pokud najdeme shodu, tak jméno stroje vložíme do proměnné příjemce a odešleme zprávu. No a tento kód se spustí paralelně na všech PC, které jsme pomocí get-adcomputer dostali z Active Directory.

Jak to všechno použijeme? Nejdřív si vytvoříme to workflow, viz zdroják výše. Uložíme to třeba jako send_message_workflow.ps1. Workflow musíme spustit podobně jako se spouští funkce, tedy takovou tou dvoutečkovou konvencí. (tečka - mezera - tečka - zpětné lomítko - název):

. .\send_message_workflow.ps1

No a teď už můžete volat workflow pomocí jména a díky parametrům vybíráte, komu chcete poslat zprávu a jak má ta zpráva vypadat.

send-message -group vedeni -message "Jste nejslabší, máte padáka. ;-)"

send-message -group personalni -message "Opravdu má sekretářka ředitele 50 tisíc měsíčně?"

send-message -group it -message "Nefunguje mi solitare, co mám celý den dělat?"

A to je vše. Můžete zkoušet, opravovat a testovat. Třeba vyzkoušejte, jestli ten vnitřní foreach nemůže být taky foreach -parallel. Ale radši si vymyslete svoje znění zpráv. :-)

Poslední aktualizace - Středa, 2. Března 2016 22:35
 
 
 
Page 1 of 1
© TNX alias Jan Kovář. Původní design stránky byl určen pro CMS Joomla! a vytvořen společností Siteground web hosting