Cvičebnica z PowerShellu, diel 4.

PowerShell ISE

Zoznámte sa s PowerShell ISE

Spustite ISE pod právami administrátora

Overte správanie pri otváraní uložených skriptov

Otvorenie existujúcich skriptov spôsobí problémy pri spúšťaní.

File C:\Users\novotnyr\hello.ps1 cannot be loaded because the execution of scripts is  disabled on this system. Please see "get-help about_signing" for more details.
At line:0 char:0

Zmeniť možno politiku vykonávania skriptov

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

Následne treba odsúhlasiť v GUI zmenu politiky. Táto politika umožní spúšťať všetky skripty, ale tie, ktoré sa stiahli z webu, musia byť digitálne podpísané.

Konštrukcie z procedurálneho programovania

Oboznámte sa so syntaxou premenných. Vypočítajte cenu s DPH.

$cena = 1200
$dph = 0.21
($cena * $dph) + $dph

Premenné v Powershelli sú uvádzané dolármi, podobne ako v PHP, či Perli.

Overte dátový typ premennej $cena

$cena | Get-Member

Dátové typy využívajú objektový model z .NET frameworku.

Zistite názvy najčítanejších článkov za posledné 4 hodiny na portáli SME.sk.

$rss = (New-Object System.Net.WebClient).DownloadString("http://rss.sme.sk/rss/rss.asp?id=smenajcit4")
$xml = [xml] $rss;
$xml.rss.channel.item | % {$_.title}
  • Metódou DownloadString stiahneme reťazec.
  • Pretypujeme ho na XML objekt reprezentovaný typom [xml]
  • po elementoch v strome skáčeme klasickou bodkovou notáciou
  • dokonca atribúty sa zjavia ako vlastnosti (properties)

Zistite kurz českej koruny z http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

$currency = "CZK"
$xml = [xml] (New-Object System.Net.WebClient).DownloadString("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml")
$xml.Envelope.Cube.Cube.Cube | ? {$_.currency -eq $currency } | select rate
  • použijeme filozofiu z predošlej úlohy
  • bonus: atribúty sa zjavia ako vlastnosti (properties)
  • menné priestory v XML nemusíme vôbec riešiť.
  • pri porovnávaní pozor na operátor! Používame -eq, a nie ==.

Vypíšte 10x text Budem si robiť domáce úlohy.

for ($i = 0; $i -lt 10; $i++) {
    echo "Budem si robiť domáce úlohy."
}

Cyklus for využíva klasickú C/C++/Java/C# syntax. Pozor na

  • deklaráciu premenných
  • porovnávanie dvoch hodnôt: namiesto < použite -lt.

Alternatívne: príkaz echo nie je povinný, keďže samotný reťazec predstavuje výraz, ktorý sa pošle do rúry a teda do výstupu.

for ($i = 0; $i -lt 10; $i++) {
    "Budem si robiť domáce úlohy."
}

Vypíšte 10x text Budem si robiť domáce úlohy., pričom použite `while

$i = 0
while ($i -lt 10) {
    "Budem si robiť domáce úlohy."
    $i++
}

Napíšte ľubovoľný nekonečný cyklus

Zlé riešenie:

while (true) {
    "Budem si robiť domáce úlohy."
}

Hláška je

The term 'true' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Výraz true v Powershelli nie je definovaný.

Alternatívne:

while (1) {
    "Budem si robiť domáce úlohy."
}

Každý nenulový výraz sa vyhodnotí na booleovskú hodnotu pravda.

Spočítajte frekvencie prípon súborov v adresári

$extensionMap = @{}
ls -R D:\MP3 | ? { $_.Mode -notmatch "d" } | % { 
    if(! $extensionMap.containsKey($_.Extension)) {
        $extensionMap[$_.Extension] = 1
    } else {
        $extensionMap[$_.Extension]++
    }
}

$extensionMap
  • Využime dátovú štruktúru hash; analógiu HashMap z iných jazykov.
  • Prázdny hash vytvoríme cez @{}, získame objekt typu System.Collections.Hashtable
  • Vieme pristupovať cez [...] notáciu.
  • Existenciu kľúča overíme cez metódu containsKey().

Spočítajte frekvencie prípon súborov v adresári so zgrupovaním

ls -R D:\MP3 | Group-Object Extension | Sort Count | ft Name, Count -a

Group-Object dokáže zgrupovať veci do množín podľa rozličných kritérií.

Zotrieďte danú hashtabuľku frekvencií podľa počtu výskytov

$frekvencie = @{".m3u" = 3; ".mp3" = 790; ".flac" = 168; ".jpg" = 79}
$frekvencie.GetEnumerator() | sort Name
  • hash môžeme vytvoriť aj s hodnotami: uvádzame ich v tvare kľúč=hodnota a oddeľujeme bodkočiarkou.
    • častá chyba je oddeľovať ich čiarkou!
  • ak chceme triediť hash, musíme získať jeho enumerátor (analógia Iterator z Javy), ktorý z každej položky vytvorí separátny objekt a pošle ho do rúry. Klasické $frekvencie | Sort nebude fungovať!

Funkcie

Vytvorte funkciu Get-Hello, ktorá vypíše 10x “Hello World”

function Get-Hello {
    1..10 | % { "Hello World" }
}

Funkciu zavoláme cez

Get-Hello

Funkcie sa majú tváriť ako cmdlety a teda by mali dodržiavať konvenciu slovesopodstatné meno.

Vytvorte funkciu Get-Hello, ktorá vypíše zadaný počet krát “Hello World”

function Get-Hello($count) {
    1..$count | % { "Hello World" }
}

Get-Hello 3

Pri parametroch je často vhodné uviesť implicitnú hodnotu. Ak totiž zavoláme len

Get-Hello

Uvidíme výpis:

Hello World
Hello World

Funkcia totiž bude iterovať od 1..0, čiže dvakrát. Úprava:

function Get-Hello($count=1) {
    1..$count | % { "Hello World" }
}

Vytvorte funkciu Write-RepeatedMessage, ktorá vypíše zadaný počet krát text

function Write-RepeatedMessage($message, $count = 1) {
    1..$count | % { $message }
}

Správne volanie:

Write-RepeatedMessage "Hello World" 2

Zlé volanie, aj keď prirodzené:

Write-RepeatedMessage("Hello World", 2)

Vypíše totiž:

Hello World
2

Toto nefunguje! Funkcie sa majú tváriť ako cmdlety, preto žiadne zátvorkové volanie nefunguje. Toto nesprávne volanie zavolá funkciu s jedným parametrom typu dvojprvkové pole. PowerShell ho vypíše raz a keďže polia sa transformujú na jednotlivé prvky poslané do rúry, uvidíme presne tento výpis.

Skúste si to napríklad s

Write-RepeatedMessage("Hello World", 2, "Ding", "Dong")

Parametre oddeľujeme medzerami!

WTF správanie môžeme vylepšiť dodaním dátových typov

function Write-RepeatedMessage([string] $message, [int] $count = 1) {
    1..$count | % { $message }
}

Write-RepeatedMessage("Hello World", 2)

Toto povedie k výpisu:

Hello World 2

Vytvorte funkciu, ktorá vypíše čísla od hranice po hranicu s krokom

function Get-Sequence([int] $from, [int] $to, [int] $step = 1) {
    for($i = $from; $i -le $to; $i = $i + $step) {
        $i
    }
}

Volanie:

Get-Sequence 1 10 3

Aby sme predišli kadejakému WTF, deklarujme dátové typy. Ak máme len hlavičku

function Get-Sequence($from, $to, $step) {

Môžeme zavolať:

Get-Sequence "" "Badger Badger Badger Badger Mushroom Mushroom" "Badger "

A máme nekonečný cyklus.

Ak deklarujeme dátové typy, uvidíme hlášku:

Get-Sequence : Cannot process argument transformation on parameter 'to'. Cannot convert value "Badger Badger Badger Badger Mushroom Mushroom" to type "System.
Int32". Error: "Input string was not in a correct format."

Vytvorte funkciu Get-HomeDirectory, ktorá pre zadaného používateľa vráti jeho domovský adresár

function Get-HomeDirectory($username) {
    $sid = (gwmi win32_useraccount -filter "name = '$username'").sid
    (gwmi win32_userprofile -filter "sid = '$sid'").LocalPath
}

Volanie:

Get-HomeDirectory "rn"

Výpis [na Windows 8.1]:

C:\Users\rn

Využijeme funkcie z WMI. Špecialita je interpolácia reťazcov: ak máme premennú $username, a chceme ju použiť vo vnútri reťazca, nemusíme ich lepiť. Dolárové premenné vo vnútri reťazcov sa automaticky nahradia ich hodnotami:

"name = '$username'"

pre $username = "rn" po interpolácii vznikne reťazec "name = 'rn'".

Vytvorte funkciu Get-HomeDirectory, ktorá vypíše domovský adresár používateľa z rúry

function Get-HomeDirectory {
    foreach($username in $input) {
        $sid = (gwmi win32_useraccount -filter "name = '$username'").sid
        (gwmi win32_userprofile -filter "sid = '$sid'").LocalPath
    }
}

Volanie:

"rn", "UpdatusUser" | Get-HomeDirectory

Každá funkcia má skrytú premennú $input, ktorá je kolekcia s prvkami prichádzajúcimi z rúry.

Vytvorte funkciu, ktorá zistí celkové veľkosti adresárov (rekurzívne)

function Measure-Directory {
    foreach($item in $input) {
        $size = (dir $item.FullName -Recurse | Measure-Object -Sum -Property Length).Sum
        @{$item.FullName = $size}
    }
}

Volanie:

ls D:\MP3 | Measure-Directory

Alebo:

"D:\MP3\Ectasy of Saint Theresa", "D:\MP3\Happy Melon"  | Get-Item | Measure-Directory

Očíslujte položky z rúry

function Enumerate-Items {
    $itemIndex = 0;
    foreach($item in $input) {
        @{$itemIndex = $item}
        $itemIndex++
    }
}

Volanie:

dir | Enumerate-Items

Očíslujte položky z rúry [alternatívna syntax]

function Enumerate-Items {
    begin {
        $itemIndex = 0;
    }
    process {
        @{$itemIndex = $_}
        $itemIndex++
    }
}

Funkcia môže pozostávať z troch blokov:

  • begin: vykoná sa pred spracovaním prvého objektu z rúry
  • end: vykoná sa po spracovaní posledného objektu z rúry
  • process: vykoná sa pre každý objekt z rúry samostatne. V premennej $_ sa zjaví aktuálny objekt, ktorý prichádza z rúry.

Vytvorte filter, ktorým spočítate veľkosť adresárov z rúry

filter Measure-Directory {
    $size = (dir $_.FullName -Recurse | Measure-Object -Sum -Property Length).Sum
    @{$_.FullName = $size}
}

Funkcia, ktorá má len blok process, sa nazýva filter. Riešenie je ekvivalentné

function Measure-Directory {
    foreach($item in $input) {
        $size = (dir $item.FullName -Recurse | Measure-Object -Sum -Property Length).Sum
        @{$item.FullName = $size}
    }
}

a ekvivalentné:

function Measure-Directory {
    process {
        $size = (dir $_.FullName -Recurse | Measure-Object -Sum -Property Length).Sum
        @{$_.FullName = $size}
    }
}

Zistite, ktoré procesy sú systémovo náročné (> 60% CPU)

filter Get-CpuHeavyProcess {
    if($_.PercentProcessorTime -ge 60) {
        $obj = New-Object PSObject | Select Name, CPU
        $obj.Name = $_.Name;
        $obj.CPU = $_.PercentProcessorTime;
        $obj
    }
}
gwmi Win32_PerfFormattedData_PerfProc_Process | Get-CpuHeavyProcess

Vyrobíme jednoduchý filter, ktorý sa díva na vlastnosť PercentProcessorTime.

Zároveň demonštrujeme dynamické vytváranie objektu.

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *