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 typuSystem.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 sloveso–podstatné 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úryend
: vykoná sa po spracovaní posledného objektu z rúryprocess
: 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.