čtvrtek 25. června 2009

Scripting Games 2009 - Event 2

Úkol číslo dva byl nazván The Long Jump.

Divize Advanced
Z daného souboru (XLS) bylo potřeba zjistit délky skoků jednotlivých sportovců a na základě výkonů v sezóně určit zda splnili očekávání do nich vkládaná.

  1. $path = "C:\sg2009\LongJump_Adv2.xls"
  2. $xls = New-Object -com Excel.Application
  3. $xls.Visible = $true
  4. $wrkbk = $xls.Workbooks.Open($path)
  5. $format = 23
  6. $wrkbk.SaveAs('C:\sg2009\result.csv',$format)
  7. $wrkbk.Close($true)
  8. $xls.Quit()
  9. $data = Import-Csv C:\sg2009\result.csv
  10. foreach ($row in $data) {
  11. if ($row.'Jump 1' -eq 'x') { $row.'Jump 1' = 0 }
  12. if ($row.'Jump 2' -eq 'x') { $row.'Jump 2' = 0 }
  13. if ($row.'Jump 3' -eq 'x') { $row.'Jump 3' = 0 }
  14. if (([double]$row.'Jump 1' -ge [double]$row.'Jump 2') -and ([double]$row.'Jump 1' -ge [double]$row.'Jump 3')) {
  15. [double]$row.Result = $row.'Jump 1'
  16. }
  17. elseif (([double]$row.'Jump 2' -ge [double]$row.'Jump 1') -and ([double]$row.'Jump 2' -ge [double]$row.'Jump 3')) {
  18. [double]$row.Result = $row.'Jump 2'
  19. }
  20. else {
  21. [double]$row.Result = $row.'Jump 3'
  22. }
  23. if ($row.Result -lt $row.'Season Average') {
  24. $row.'Exceed/Achieve/Under Perform ' = '1.Under Perform'
  25. }
  26. elseif ($row.Result -eq $row.'Season Average') {
  27. $row.'Exceed/Achieve/Under Perform ' = '2.Achieve'
  28. }
  29. else {
  30. $row.'Exceed/Achieve/Under Perform ' = '3.Exceed'
  31. }
  32. }
  33. $data | sort 'Exceed/Achieve/Under Perform ', Result -Descending | `
  34. Export-Csv C:\sg2009\result.csv -Force -NoTypeInformation
Celou úlohu jsem si převedl do PowerShellu tím, že jsem zavolal Excel a použil SaveAs... / CSV. Potom jsem již jen načel data pomocí Import-Csv a porovnal výsledky za sezónu. Výsledek jsem zapsal do potřebného sloupce a poté jen výsledky vyexportoval do nového CSV souboru.

Divize Beginners
Obsahovala jednoduchou úlohu pro dotaz do WMI. V PowerShellu naprosto jednoduchá věc. Celá úloha byla pouze "ztížena" výpisem různých barviček. Tentokrát jsem úkol řešil jako jednoduchou funkci, kdy jsem navíc přidal možnost zadání jména vzdáleného počítače.

  1. function Get-LongJumpResults {
  2. param (
  3. $computer = "localhost"
  4. )
  5. $headerColor = "Green"
  6. $speedColor = "Yellow"
  7. $strengthColor = "Magenta"
  8. $agilityColor = "Cyan"
  9. $data = gwmi Win32_Processor -ComputerName $computer
  10. Write-Host "Strength evaluation for $computer" -ForegroundColor $headerColor
  11. Write-Host "Speed ... $($data.MaxClockSpeed)" -ForegroundColor $speedColor
  12. Write-Host "L2 cache size: $($data.L2CacheSize)" -ForegroundColor $speedColor
  13. Write-Host "L2 cache speed: $($data.L2CacheSpeed)" -ForegroundColor $speedColor
  14. Write-Host "L3 cache size: $($data.L3CacheSize)" -ForegroundColor $speedColor
  15. Write-Host "L3 cache speed: $($data.L3CacheSpeed)" -ForegroundColor $speedColor
  16. Write-Host "Strength ..." -ForegroundColor $strengthColor
  17. Write-Host "Number of Cores: $($data.NumberOfCores)" -ForegroundColor $strengthColor
  18. Write-Host "Number of logical processors: $($data.NumberOfLogicalProcessors)" -ForegroundColor $strengthColor
  19. Write-Host "Name: $(($data.Name).trim())" -ForegroundColor $strengthColor
  20. Write-Host "Agility ..." -ForegroundColor $agilityColor
  21. Write-Host "Address width: $($data.AddressWidth)" -ForegroundColor $agilityColor
  22. } #function Get-LongJumpResults
Opět nic složitého.

pátek 19. června 2009

Audit skupin v Active Directory

Dnes mě na chatu chytil jeden z přátel zabývajících se bezpečností. Líbil se mu report zobrazující lokální administrátory na koncových stanicích a chtěl něco podobného vytvořit pro skupinu Domain Admins. Ptal se mne na možnosti a mou první odpovědí bylo: PowerShell.

První nástřel byl tento:
Get-QADGroupMember 'domain.com/CZ/Domain Admins'

Výstupem příkazu je seznam členů této skupiny. To mělo úspěch a samozřejmě přišla další otázka: "Lze porovnat výsledky proti nějakému danému stavu?" Ano, úkol jak dělaný pro Compare-Object. Celý skript pak vypadal následovně.
  1. function Compare-ADGroup {
  2. param (
  3. [string]$group = 'domain.com/CZ/Domain Admins',
  4. [switch]$snapshot
  5. )
  6. if ($snapshot) {
  7. # save state as snapshot
  8. Get-QADGroupMember $group | `
  9. Select-Object SamAccountName, FirstName, LastName | `
  10. Export-Clixml ./snapshot.xml
  11. }
  12. else {
  13. Get-QADGroupMember $group | `
  14. Select-Object SamAccountName, FirstName, LastName | `
  15. Export-Clixml ./current.xml
  16. # load to variables, sort to prepare for Compare-Object
  17. $s = (Import-Clixml ./snapshot.xml) | Sort-Object SamAccountName
  18. $c = (Import-Clixml ./current.xml) | Sort-Object SamAccountName
  19. # compare objects based on SamAccountName
  20. Compare-Object -ReferenceObject $s -DifferenceObject $c -Property SamAccountName
  21. } # else
  22. } # function Compare-ADGroup
První spuštění musí být s parametrem -Snapshot. Tím se vytvoří referenční soubor se "správnými" daty. Skript by šel ještě vylepšit o kontrolu existence souboru snapshot.xml nebo například o vložení časové značky do souboru current.xml.

středa 10. června 2009

Scripting Games 2009 - Event 1

Určitě vám neuniklo, že byl neoficiálně odstartován další ročník Scripting Games. Nejlepším rozcestníkem je nyní zřejmě stránka PoshCode.org, která zajišťuje prostor pro vkládání hotových skriptů. První úkol má název The 100 meter dash.

Divize Advanced
Úkolem je najít ve vstupním textovém souboru řádky obsahující text a vypsat tři nejkratší. Mé řešení bylo následujcí:

Get-Content "./Personal Information Cards_ADV1.txt" | `
Where-Object {$_ -match "\S"} | `
Sort-Object Length | `
Select-Object -First 3

Celá práce probíhá na jedné řádce.
  1. Načtení souboru.
  2. Vyfiltrování řádek, které obsahují text. Zde vyjádřeno pomocí regulárního výrazu \S - pusť všechno, co není pouze mezera.
  3. Seřaď řádky podle délky.
  4. Vypiš tři nejkratší.
Celý úkol byl relativně jednoduchý, důležité bylo přijít na filtrování prázdných řádek. Někteří použili v druhém kroku funkci trim().

Divize Beginners
Byla na rozdíl od advanced relativně složitá. Vše bylo způsobeno jedním malým "překlepem" kdy ve vstupním souboru byla jedna položka oddělena mezerou místo tabulátorem. Jelikož jsem chtěl mít hotovo rychle, využil jsem letošního pravidla: "Vše, co je dovoleno v reálném světě, je dovoleno i v soutěži." Ručně jsem opravil "chybnou" řádku a skript byl poté již jednoduchý:

Import-Csv '100 Meter Event.txt' -Delimiter "`t" | `
  Sort-Object Time | `
  Select-Object -First 3
  1. Použil jsem cmdlet Import-Csv z PowerShellu verze 2. Ve verzi 2 je totiž u tohoto cmdletu nový parametr, pomocí nějž určíte, jak je soubor oddělen. Výborná věc pro české prostředí, kde je standardním oddělovačem středník.
  2. Výstupem z první roury byly objekty, které jsem seřadil podle času
  3. a pak jen vypsal první tři.
K tomuto úkolu se ještě vrátím a pomocí regulárních výrazů si poradím s problémovou řádkou.

Jelikož jsem u obou řešení používal aliasy, můžete se na mé "opravdové" verze v beginners a advanced divizích podívat přímo na PoshCode.org.

pátek 29. května 2009

Automatizace a Scripting Games

Dnes ráno mne zaujaly na Twitteru dvě zprávy:
  1. Má smysl automatizovat úplně všechno? Připomíná mi to mé poznámky na prezentacích PowerShelu, když říkám, že ne vždy je PowerShell efektivní. Občas prostě není efektivní vůbec nic kromě manuální práce :) Samozřejmě to neplatí při výrobu skriptů pro studijní účely. Přečtěte si původní článek a jestli chcete, nechte mi zde pod článkem komentář.
  2. Summer Scripting Games 2009 - podrobnější informace byly zveřejněny na novém blogu Hey, Scripting Guy! Letos je mottem vzdělání, nikoli soutěž a všechna témata se budou věnovat desetiboji (vzdělávacímu samozřejmě). Cílem je přiblížit průběh více reálnému světu a bude např. možné použít části kódu jiných soutěžících. Zároveň byly potvrzeny čtyři kategorie - VBScript a PowerShell; oba jazyky pro Beginner a Advanced divizi. 

středa 20. května 2009

Hledání adresářů podle obsahu

Jedna z poznámek na Twitteru mě zavedla ke konzoli PowerShellu. Chtěl jsem si vyzkoušet, jak je jednoduché vyhledat adresáře podle specifického zadání. Konkrétní dotaz zněl: "Chci všechny adresáře začínající písmenem L, které obsahují soubory *.dwg". Dotaz jsem si upravil na "... všechny soubory s příponou PS1, které jsou v adresáři začínajícím na zzz.

Vypadl mi následující one-liner:

ls -i *.ps1 -r | select Directory -u | % {if((Split-Path $_.Directory -le) -like 'zzz*') {$_}}

Lépe je zřejmě čitelný takto:

Get-ChildItem -Include *.ps1 -Recurse | `
Select-Object -Property Directory -Unique |`
ForEach-Object {
if ( (Split-Path $_.Directory -Leaf) -like 'zzz*') { $_ }
}

V první části roury probíhá rekurzivní hledání všech PS1 souborů. Poté vybereme jména všech adresárů a dále hledáme ty, jejichž jméno začíná na zzz. pokud některý podmínku splňuje, tak vypíšeme celou cestu k adresáři.

pondělí 18. května 2009

Scripting Games 2009

Konečně bylo uveřejněno datum letních Scripting Games 2009. Více informací je k nalezení na stránkách Script centra. Vypadá to, že letos se bude soutěžit v PowerShellu a VB Scriptu a Perl tedy zřejmě odpadá. Pokud se chcete dozvědět více, podívejte se na stránky Scripting Games a zapátrejte v archivu.

Letos se na pořádání budou také podílet PowerShellCommunity.org a PoShCode.org.

Profil autora těchto stránek na stránkách Scripting Games (v roce 2007 jsem absolvoval VBS beginners divizi).

čtvrtek 14. května 2009

Hej, mistře Šelíku!

Vítejte zpátky u mistra Šelíka. V posledním TechNet Flash zpravodaji řešil následující problém.

No, dejme tomu - DateDiff je dobrá funkce, ale kdo si má pamatovat, kdy si naposledy měnil heslo. DateDiff (resp. odčítání dvou dat) bych použil v případě, že bych chtěl například zjistit, kolik dní zbývá do Vánoc.

PS C:\> $vanoce = '2009/12/24'
PS C:\> ($vanoce - (get-date)).Days
223

V případě zjištění délky používání hesla je lepší sáhnout přes ADSI na vlastnost PasswordAge.

PS C:\> [ADSI]$user="WinNT://czvm01/administrator,user"
PS C:\> $user.PasswordAge
97399082
PS C:\> ($user.PasswordAge).value/86400
1127,30418981481

První výsledek nám vrátil stáří hesla v sekundách, takže jsme jej přepočítali na dny. Vidíme, že administrátorské heslo na tomto počítači nebylo změněno hodně dlouho :) V případě, že by vás zajímalo stáří hesla pro účet v Active Directory, stačí změnit první řádek na následující variantu:

PS C:\> [ADSI]$user="WinNT://domain.name/administrator,user"

a v proměnné $user budeme mít uložen účet doménového administrátora.

Pokud víte, že informaci o stáří hesla budete využívat častěji, můžete si předchozí kód uložit do skriptu.

function Get-PasswordAge {

param (
[string]$scope = "$env:computername",
[string]$user = "administrator"
)

[ADSI]$ADSIobj="WinNT://$scope/$user,user"
"$user : $([Math]::Round(($ADSIobj.PasswordAge).value/86400))"
}

PS C:\> Get-PasswordAge
1127
PS C:\> Get-PasswordAge -user $env:USERNAME -scope $env:USERDOMAIN
86

Jediným doplněním je závěrečné zaokrouhlení dnů na celá čísla pro lepší přehlednost.

Banner mistra Skriptíka je stažen ze stránek TechNet Flash zpravodaje. Děkuji týmu TechNetu za možnost jeho použití pro potřeby tohoto článku.