Contents of this directory is archived and no longer updated.

Posts on this page:

Scripting Games 2009 Бег на 110 метров с барьерами.

Beginner Division

Задача:

  • В исходном файле скрипта найти все ошибки и исправить их. При запуске скрипта на рабочем столе должны появиться 3 ярылка: на сам скрипт, на веб-сайт Hey, Scripting Guys! и ярлык на блокнот (notepad.exe).

Решение:

Всё копировать не буду, а только приведу уже готовый скрипт. Сам текст скрипта можно взять тут: Hey, Scripting Guy! Opening Ceremonies and 2009 Scripting Games Event 6 Details (Beginner and Advanced; 110-meter hurdles). Исходные ошибочные строки привёл в комментарии:

#==========================================================================
#
# PowerShell:  AUTHOR: Ed Wilson , msft,  6/15/2009
#
# NAME: Beg_6.ps1
#
# COMMENT: Key concepts are listed below:
#1. Uses wscript.shell to create three shortcuts on the desktop. The first is a shortcut
#2. to this actual script. It uses the scriptfullName property to assign the path.
#3. The second is a simple Web site URL shortcut. The third one is a shortcut to
#4. Notepad.
#==========================================================================
$ErrorActionPreference = "SilentlyContinue"
Set-PSDebug -Strict
New-Variable -Name objShell #instance of the wshSHell object
New-Variable -Name strDesktop #pointer to desktop special folder
New-Variable -Name objShortCut #used to set properties of the shortcut. Comes from using createShortCut
New-Variable -Name objURL #used to set properties of webshortcut.
# было: $oShell = New-Object -ComObject ("WScript.Shell") - ошибка в имени переменной
$objShell = New-Object -ComObject ("WScript.Shell")
$strDesktop = $objShell.SpecialFolders.item("Desktop")

$objShortCut = $objShell.CreateShortcut($strDesktop + "\Shortcut Script.lnk")
# было: $objShortCut.TargetPath = $MyInvocation.ScriptName - неверное свойство
$objShortCut.TargetPath = $MyInvocation.MyCommand
$objShortCut.WindowStyle = 0
$objShortCut.Hotkey = "CTRL+SHIFT+F"
$objShortCut.IconLocation = "notepad.exe, 2"
$objShortCut.Description = "Shortcut Script"
$objShortCut.WorkingDirectory = $strDesktop
# было: $objShortCut.Save - при вызове метода забыли скобки
$objShortCut.Save()

# $wshShell = New-Object -ComObject wscript.shell - не нужно совсем
# было: $objURL = $objShell.CreateShortcut($strDesktop & "\The Microsoft Scripting Guys.url")
# вместо + поставили & из VBS
$objURL = $objShell.CreateShortcut($strDesktop + "\The Microsoft Scripting Guys.url")
$objURL.TargetPath = "http://www.ScriptingGuys.com"
# было: $objURL.Discription = "Scripting Guys". Такого свойства в URL файлах нету.
$objURL.Save()

# было: $wshNetwork = New-Object -ComObject wscript.network - не нужно свсем
# было: $objShortCut = $objShell.CreateShortcut($strDesktop + "\notepad.link")
# расширение не LNK, а LINK
$objShortCut = $objShell.CreateShortcut($strDesktop + "\notepad.lnk")
# было: $objShortCut.TargetPath = "notpad.exe" - пропустили букву E
$objShortCut.TargetPath = "notepad.exe"
$objShortCut.IconLocation = "notepad.exe, 0"
$objShortCut.description = "notepad"
$objShortCut.Save()

Если запустить этот скрипт из файла, то получится 3 ярлыка и первый будет вести именно на файл самого скрипта.

Advanced Division

и снова задача на парсинг текста. Потребуется файл network trace_adv6.txt из Competitors pack.

Задача:

  • распарсить вывод tracert и показать участки, на которых наблюдается замедление скорости (т.е. время прыжка увеличивается)

Решение:

Самая первая задача, которая перед нами встаёт – создание регулярного выражения. Выражение у меня получилось вот такое:

^\d+\W+(\d+)\D+(\d+)\D+(\d+) ms  (.*)

Что оно делает: оно откидывает порядковый номер прыжка (hop), любую небуквенную последовательность (в общем смысле [A-Za-z0-9]) и выбирает первую последовательность чисел. Эта последовательность будет будет являться временем первой попытки посылки ICMP пакета. Далее откидывается любая нечисловая последовательность и выбирается первая же числовая последовательность, которая будет являться второй попыткой посылки ICMP пакета. То же самое делаем до 3-й попытки текущего прыжка включительно. После выкидываем пробел и последовательность букв “ms”, за ней 2 пробела и захватываем всё до конца строки, что будет являеться адресом и/или именем маршрутизатора. Т.к. перед порядковыми номерами прыжков (до 9 включительно) присуствует пробел, то его можно средать методом Trim() и уже подставлять выражение. Из захваченного времени нужно на лету посчитать среднее значение. И вот что у меня вышло:

[↓] [vPodans] gc "Network Trace_Adv6.txt" | ?{$_.trim() -match "^\d+\W+(\d+)\D+(\d+)\D+(\d+) ms  (.*)"} | %{
>>     $current = "" | Select @{n='Average';e={[int](([int]$matches[1]+[int]$matches[2]+[int]$matches[3])/3)}},
>>     @{n='Name';e={$matches[4]}}
>>     $current
>> } | ft -a
>>

Average Name
------- ----
      1 r10.ntwk.nwtraders.com [192.168.227.82]
      1 r20.ntwk.nwtraders.com [192.168.169.1]
      1 r50.ntwk.nwtraders.com [192.226.42.47]
     13 r70.ntwk.nwtraders.com [192.226.42.12]
     34 r12.ntwk.nwtraders.com [192.226.42.9]
     34 r40.ntwk.nwtraders.com [192.226.42.22]
    104 r22.ntwk.nwtraders.com [192.226.34.80]
    105 r32.ntwk.nwtraders.com [192.226.47.10]
    125 r35.ntwk.nwtraders.com [192.226.41.198]
    173 r37.ntwk.nwtraders.com [192.226.38.14]
    173 r38.ntwk.nwtraders.com [192.226.226.119]
    389 192.168.216.5
    390 r60.ntwk.nwtraders.com [192.168.236.9]


[↓] [vPodans]

Теперь нужно определить на каких участках происходит замедление. Я решил поэтапно циклом For проверять каждый элемент массива – меньше ли он, чем следующий элемент или нет. Если он равен или больше следующего элемента, то ничего делать не надо, т.к. замедления нету. Если меньше, то он является пограничным этапом, где происходит замедление и выводим его на экран. Привожу уже готовый код и полученный результат:

$sum = @()
gc "Network Trace_Adv6.txt" | ?{$_.trim() -match "^\d+\W+(\d+)\D+(\d+)\D+(\d+) ms  (.*)"} | %{
    $current = "" | Select @{n='Average';e={[int](([int]$matches[1]+[int]$matches[2]+[int]$matches[3])/3)}},
    @{n='Name';e={$matches[4]}}
    $sum += $current
}
$(for ($i = 0; $i -le $sum.Count; $i++ ) {
    if ($sum[$i].Average -lt $sum[$i + 1].Average) {$sum[$i]}
    if ($i -eq ($sum.Count - 1)) {$sum[$i]}
}) | ft @{l='Average';e={$_.Average};a='left'}, @{l='Name';e={$_.name}} -AutoSize
[↓] [vPodans] $sum = @()
[↓] [vPodans] gc "Network Trace_Adv6.txt" | ?{$_.trim() -match "^\d+\W+(\d+)\D+(\d+)\D+(\d+) ms  (.*)"} | %{
>>     $current = "" | Select @{n='Average';e={[int](([int]$matches[1]+[int]$matches[2]+[int]$matches[3])/3)}},
>>     @{n='Name';e={$matches[4]}}
>>     $sum += $current
>> }
>> $(for ($i = 0; $i -le $sum.Count; $i++ ) {
>>     if ($sum[$i].Average -lt $sum[$i + 1].Average) {$sum[$i]}
>>     if ($i -eq ($sum.Count - 1)) {$sum[$i]}
>> }) | ft @{l='Average';e={$_.Average};a='left'}, @{l='Name';e={$_.name}} -AutoSize
>>

Average Name
------- ----
1       r50.ntwk.nwtraders.com [192.226.42.47]
13      r70.ntwk.nwtraders.com [192.226.42.12]
34      r40.ntwk.nwtraders.com [192.226.42.22]
104     r22.ntwk.nwtraders.com [192.226.34.80]
105     r32.ntwk.nwtraders.com [192.226.47.10]
125     r35.ntwk.nwtraders.com [192.226.41.198]
173     r38.ntwk.nwtraders.com [192.226.226.119]
389     192.168.216.5
390     r60.ntwk.nwtraders.com [192.168.236.9]


[↓] [vPodans]

А теперь обратите внимание на одну вещь, о которой не все знают:

  ft @{l='Average';e={$_.Average};a='left'}

при форматировании Format-Table вы можете атрибутум A (от слова align) двигать содержимое колонки относительно названия. В первом примере у меня стандартное форматирование и выравнивание Avarage по правому краю. Здесь же я содержимое выравнил по левому краю, чтобы не сливались цифры. Хотя это решается удалением –AutoSize, но мне нравится этот ключ :-) вобщем, об этой фиче не забывайте.

Beginner Division

Summer Scripting Games 2009 задача на работу с реестром.

Задача:

  • Найти текущее значение максимального количества закачек в Internet Explorer
  • Увеличить это число на другое значение
  • при чтении этого значения предусмотреть проверку существования этого параметра

Решение:

Ключи и значения реестра для этой задачи можно найти тут: http://support.microsoft.com/kb/282402. В принципе, очень просто тут:

$path = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings'
if (!(Test-Path $path)) {New-Item -ItemType Registry -Path $path -Force}
if (!(Get-ItemProperty $path).MaxConnectionsPer1_0Server) {
    Write-Warning "MaxConnectionsPer1_0Server property doesn't exist"
    [void](New-ItemProperty -Path $path -Name 'MaxConnectionsPer1_0Server' -Value 10 -PropertyType 'DWord')
} else {"MaxConnectionsPer1_0Server is: " + (Get-ItemProperty $path).MaxConnectionsPer1_0Server}
if (!(Get-ItemProperty $path).MaxConnectionsPerServer) {
    Write-Warning "MaxConnectionsPerServer property doesn't exist"
    [void](New-ItemProperty -Path $path -Name 'MaxConnectionsPerServer' -Value 10 -PropertyType 'DWord')
} else {"MaxConnectionsPerServer is: " + (Get-ItemProperty $path).MaxConnectionsPerServer}

и вот вывод:

[↓] [vPodans] $path = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings'
[↓] [vPodans] if (!(Test-Path $path)) {New-Item -ItemType Registry -Path $path -Force}
[↓] [vPodans] if (!(Get-ItemProperty $path).MaxConnectionsPer1_0Server) {
>>     Write-Warning "MaxConnectionsPer1_0Server property doesn't exist"
>>     [void](New-ItemProperty -Path $path -Name 'MaxConnectionsPer1_0Server' -Value 10 -PropertyType 'DWord')
>> } else {"MaxConnectionsPer1_0Server is: " + (Get-ItemProperty $path).MaxConnectionsPer1_0Server}
>> if (!(Get-ItemProperty $path).MaxConnectionsPerServer) {
>>     Write-Warning "MaxConnectionsPerServer property doesn't exist"
>>     [void](New-ItemProperty -Path $path -Name 'MaxConnectionsPerServer' -Value 10 -PropertyType 'DWord')
>> } else {"MaxConnectionsPerServer is: " + (Get-ItemProperty $path).MaxConnectionsPerServer}
>>
WARNING: MaxConnectionsPer1_0Server property doesn't exist
WARNING: MaxConnectionsPerServer property doesn't exist
[↓] [vPodans] $path = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings'
[↓] [vPodans] if (!(Test-Path $path)) {New-Item -ItemType Registry -Path $path -Force}
[↓] [vPodans] if (!(Get-ItemProperty $path).MaxConnectionsPer1_0Server) {
>>     Write-Warning "MaxConnectionsPer1_0Server property doesn't exist"
>>     [void](New-ItemProperty -Path $path -Name 'MaxConnectionsPer1_0Server' -Value 10 -PropertyType 'DWord')
>> } else {"MaxConnectionsPer1_0Server is: " + (Get-ItemProperty $path).MaxConnectionsPer1_0Server}
>> if (!(Get-ItemProperty $path).MaxConnectionsPerServer) {
>>     Write-Warning "MaxConnectionsPerServer property doesn't exist"
>>     [void](New-ItemProperty -Path $path -Name 'MaxConnectionsPerServer' -Value 10 -PropertyType 'DWord')
>> } else {"MaxConnectionsPerServer is: " + (Get-ItemProperty $path).MaxConnectionsPerServer}
>>
MaxConnectionsPer1_0Server is: 10
MaxConnectionsPerServer is: 10
[↓] [vPodans]

как бы ничего сложного.

Advanced Division

работа с тэгами файлов. Потребуются файлы TechEd1.JPG, TechEd2.JPG и TechEd3.JPG из Competitors Pack.

Задача:

  • прочитать следующие EXIF свойства файлов:
  • Имя
  • когда снимок был сделан
  • свойство Make
  • и модель камеры, которой был сделан снимок

Решение:

Задача не такая и сложная, на самом деле, как кажется. Для начала нам потребуется класс System.Drawing.Bitmap и его метод GetPropertyItem. Для работы с этим классом нужно подключить библиотеку System.Drawing.dll:

[void][reflection.assembly]::loadfile("C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")

и создать объект System.Drawing.Bitmap:

$drawing = New-Object system.drawing.bitmap -ArgumentList .\TechEd1.jpg

Этот объект будет содержать всё нам необходимое. Чтобы посмотреть нужные нам свойства, нужно получить где-то список всех ID, которым соответствуют эти свойства. К сожалению я не нашёл такого списка на MSDN, а только отдельными частями в интернете:
http://www.exif.org/specifications.html

там в конце PDF файла есть Appendix с таблицой ID на эту тему. Если посмотреть в таблицу, то увидим, что Model находится под ID = 272. Глянем, что там есть:

[↓] [vPodans] $drawing = New-Object system.drawing.bitmap -ArgumentList .\TechEd1.jpg
[↓] [vPodans] $drawing.GetPropertyItem(271).value
67
97
110
111
110
0
[↓] [vPodans]

Как-то не очень радует такой вывод. Но если внимательно посмотреть на эти цифры, то можно заметить, что они не превышают число 256, что подсказывает, что это массив ASCII байтов. Эти ASCII байты можно сконвертировать в элемент вот так: [char]ASCII_Number. А т.к. это массив, то его нужно собрать либо методом ToString() или оператором –Join, который есть в PowerShell V2:

[↓] [vPodans] $drawing = New-Object system.drawing.bitmap -ArgumentList .\TechEd1.jpg
[↓] [vPodans] $drawing.GetPropertyItem(271).value
67
97
110
111
110
0
[↓] [vPodans] -join ($drawing.GetPropertyItem(271).value | %{[char]$_})
Canon
[↓] [vPodans]

Вот так оно всяко лучше стало. По такой же схеме выбираем и собираем все остальные свойства:

[void][reflection.assembly]::loadfile("C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")
dir *.jpg | %{
    $drawing = New-Object system.drawing.bitmap -ArgumentList $_
    $photo = "" | Select Name, Author, Make, Model, DateTaken
    $photo.Name = $_.Name
    $photo.Author = -join ($drawing.GetPropertyItem(315).value | %{[char]$_})
    $photo.Make = -join ($drawing.GetPropertyItem(271).value | %{[char]$_})
    $photo.Model = -join ($drawing.GetPropertyItem(272).value | %{[char]$_})
    $photo.DateTaken = -join ($drawing.GetPropertyItem(36867).value | %{[char]$_})
    $photo
} | ft -AutoSize
[↓] [vPodans] [void][reflection.assembly]::loadfile("C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")
[↓] [vPodans] dir *.jpg | %{
>>     $drawing = New-Object system.drawing.bitmap -ArgumentList $_
>>     $photo = "" | Select Name, Author, Make, Model, DateTaken
>>     $photo.Name = $_.Name
>>     $photo.Author = -join ($drawing.GetPropertyItem(315).value | %{[char]$_})
>>     $photo.Make = -join ($drawing.GetPropertyItem(271).value | %{[char]$_})
>>     $photo.Model = -join ($drawing.GetPropertyItem(272).value | %{[char]$_})
>>     $photo.DateTaken = -join ($drawing.GetPropertyItem(36867).value | %{[char]$_})
>>     $photo
>> } | ft -AutoSize
>>

Name        Author     Make   Model               DateTaken
----        ------     ----   -----               ---------
TechEd1.JPG Ed Wilson  Canon  Canon PowerShot G9  2009:05:12 10:41:03
TechEd2.JPG Ed Wilson  Canon  Canon PowerShot G7  2009:05:12 10:25:59
TechEd3.JPG Ed Wilson  Sony   A-9                 2009:05:12 10:26:48


[↓] [vPodans]

Вобщем, как видите, тут тоже ничего сверхсложного нету.

Summer Scripting Games 2009 Прыжки с шестом.

Beginner Division

Потребуется файл HighJumperDatabase.mdb из Competitors Pack.

Задача:

  • опросить MDB файл и вывести имя лучшего прыгуна c шестом (хотя там цифры немного странные для этой дисциплины).

Решение:

Никогда не приходилось работать с Access, поэтому пришлось честно гуглить: http://www.visualbasicscript.com/m_43134/tm.htm. Его я взял за основу, только немного подрихтовал и вот что получилось:

# создаём массив, который будет содержать все результаты
$sum = @()
# подключения к БД. Наглый копипаст с форума.# более-менее внятное описание этого кода тут:
# http://technet.microsoft.com/en-us/magazine/2009.05.scriptingguys.aspx
$adOpenStatic = 3
$adLockOptimistic = 3
$MDBConn = New-Object -comobject ADODB.Connection
$MDBConn.Open("provider=microsoft.jet.oledb.4.0;data source=$pwd\HighJumperDatabase.mdb")
$Record = New-Object -comobject ADODB.RecordSet
$Record.Open('select * from [High Jumper Data]',$MDBConn,$adOpenStatic,$adLockOptimistic)
$Record.MoveFirst()
do {
    # делаем объект текущего атлета и забиваем в него нужные значения
    $current = "" | Select @{n='Name';e={$Record.Fields.Item("Name").Value}},
    @{n='Personal Best';e={$Record.Fields.Item("Personal Best").Value}},
    @{n='Season Best';e={$Record.Fields.Item("Season Best").Value}}
    # добавляем текущего участника в массив
    $sum += $current
    # переходим на следующую итерацию
    $Record.MoveNext()
} until ($Record.EOF)
# закрываем все подключения
$Record.Close() 
$MDBConn.Close()
# сортируем и выводим лучшего спортсмена
$sum | Sort "Season Best", "Personal Best" | select Name -Last 1

Кстати, отличное решение этой задачи нашёл на VBS. Человек уложился в 4(!) строчки:

Set adoCon = CreateObject("ADODB.Connection")
adoCon.Open "DRIVER=Microsoft Access Driver (*.mdb);DBQ=HighJumperDatabase.mdb"
Winner = adoCon.Execute("SELECT TOP 1 Name FROM [High Jumper Data] ORDER BY [Personal Best] DESC")("Name")
WScript.Echo "Expected Winner: " & Winner

Есть мнение, что фанаты PowerShell должны дружно застрелиться :-) хотя это просто вопрос запроса к базе Access.

Advanced Division

потребуется файл High Jump Stats_Adv4.txt из Competitors Pack.

В файле перечислены имена прыгунов с шестом и через запятую перечислены высОты планки.

Задача:

  • на основании этих данных построить произвольный (желательно красивы) график в Excel.

Решение:

Т.к. я графики тоже никогда не рисовал, поэтому тоже пришлось обратиться к гуглу. И вышло примерно такое:

# переименовываем txt файл в CSV. Теперь не нужно конвертировать тектовый файл в
# формат Excel, т.к. при переименовании Excel сам это сделает
ren "High Jump Stats_Adv4.txt" "High Jump Stats_Adv4.csv"
# выполняем обычную рутину для создания COM объекта для Excel
$excel = New-Object -ComObject excel.application
$file = $excel.Workbooks.Open("$pwd\High Jump Stats_Adv4.csv")# | Out-Null
$excel.Visible = $false
$excel.DisplayAlerts = $false
$sheet = $excel.Worksheets.Item(1)
# добавляем диаграмму
#$chart = $excel.Charts.Add()
# задаём диапазон для диаграммы
$Range = $sheet.Range("A1:l1")
# добавляем элемент Chart с нужным диапазоном. Я выбрал 10 первых попыток
# для первого атлета. 
$chart = $excel.Charts.Add()
$chart.SetSourceData($Range)
$chart.ChartStyle = 27
# сохраняем Chart в файл формата Excel и закрываем работу
$file.SaveAs("$pwd\High Jump Stats_Adv4.xlsx")
$excel.Quit()
gps excel | stop-process
# переименовываем CSV файл обратно в TXT
ren "High Jump Stats_Adv4.csv" "High Jump Stats_Adv4.txt"

Summer Scripting Games 2009 3-е задание на парсинг текста.

Beginner Division

Потребуется файл Shot Put.txt из Competitors Pack.

Задача:

  • В файле есть 2 абзаца. Нужно первый абзац записать в файл Shot Put A.txt, а второй абзац записать в Shot Put B.txt.
  • Переименовать файл Shot Put.txt в Shot Put.old.

Решение:

Если внимательно посмотреть на файл, то в нём можно найти одну уникальную последовательность - `r`n`r`n. Она разделяет 2 абзаца. Поэтому эту последовательность можно использовать в качестве разделителя для Get-Content:

[↓] [vPodans] $file = gc '.\Shot Put.txt' -Delimiter "`r`n`r`n"
[↓] [vPodans] $file[0]
This is the first paragraph of the shot put text file. It will
need to be placed into the first text file which you will create.
The shot put is an event involving putting and heavy metal ball.
The object of the event is to throw the put as far as possible,
or to put the shot : anyway, you get the idea.




[↓] [vPodans] $file[1]
This is the second paragraph of the shot put text file. it
contains information you will need to put into the second
file which you will also create.
[↓] [vPodans]

Если со вторым абзацем понятно, то у первого очень много пробелов и пустых строк. Их можно удалить при помощи метода Trim(), который использовался уже в Event1. Собственно, само решение:

$file = gc '.\Shot Put.txt' -Delimiter "`r`n`r`n" | %{$_.trim()}
$file[0] > 'Shot Put A.txt'
$file[1] > 'Shot Put B.txt'
ren '.\Shot Put.txt' 'Shot Put.old'

Advanced Division

потребуется файл Wordlist_ADV3.txt из Competitors Pack.

Задача:

  • распарсить текстовый файл и вытащить из них слова, в которых используется не более одной уникальной гласной буквы.
  • записать эти слова в новый текстовый файл.

Решение:

В принципе, тут есть только одно простое решение (считайте, что нагло стырено у Васи):

gc .\Wordlist_ADV3.txt | ?{$_ -replace '[^AEIOUY]' -match '^(.)\1*$'} > 'Wordlist_ADV3_new.txt'

суть решения заключается в том, чтобы из каждого слова убрать все согласные и проверить, что в слове используется только одна гласная 1 или более раз. Этот регексп описан в PowerShell Cookbook на странице 494.

Beginner Division

Summer Scripting Games 2009 Тут очень простое задание из серии фаллометрии :-)

Задача:

  • Показать данные своего процессора (процессоров) в соответствии с рисунком

Решение:

Тут нам потребуется WMI класс Win32_Processor. И из него выберем нужные данные. При этом я проверю, что значения не равны $null или нулю. Если это так, то в это поле впишу текст N/A для читабельности. Вот что получилось:

$Host.UI.RawUI.BackgroundColor = "Black"
cls
$processor = gwmi win32_processor | Select AddressWidth, L2CacheSize, L2CacheSpeed, L3CacheSize,
L3CacheSpeed, MaxClockSpeed, Name, NumberOfCores, NumberOfLogicalProcessors
$processor | gm -MemberType NoteProperty | %{
    if ($processor.$($_.name) -eq $null -or $processor.$($_.name) -eq 0) {$processor.$($_.name) = "N/A"}
}
Write-Host 'Strength evaluation for LocalHost' -ForegroundColor Green
Write-Host 'Speed ... ' $processor.MaxClockSpeed `
`n'L2 Cache Size:' $processor.L2CacheSize `
`n'L2 Cache Speed:' $processor.L2CacheSpeed `
`n'L3 Cache Size:' $processor.L3CacheSize `
`n'L3 Cache Speed:' $processor.L3CacheSpeed -ForegroundColor Yellow
Write-Host Strength ... `
`n'Number of Cores:' $processor.NumberOfCores `
`n'Number of Logical Processors:' $processor.NumberOfLogicalProcessors `
`n'Name: `t`t`t`t' $processor.Name -ForegroundColor Magenta
Write-Host Agility ... `
`n'Address Width:' $processor.AddressWidth -ForegroundColor Cyan

И вот вывод:

[↓] [vPodans] $processor = gwmi win32_processor | Select AddressWidth, L2CacheSize, L2CacheSpeed, L3CacheSize,
>> L3CacheSpeed, MaxClockSpeed, Name, NumberOfCores, NumberOfLogicalProcessors
>> $processor | gm -MemberType NoteProperty | %{
>>  if ($processor.$($_.name) -eq $null -or $processor.$($_.name) -eq 0) {$processor.$($_.name) = "N/A"}
>> }
>> Write-Host 'Strength evaluation for LocalHost' -ForegroundColor Green
>> Write-Host 'Speed ... ' $processor.MaxClockSpeed `
>> `n'L2 Cache Size:' $processor.L2CacheSize `
>> `n'L2 Cache Speed:' $processor.L2CacheSpeed `
>> `n'L3 Cache Size:' $processor.L3CacheSize `
>> `n'L3 Cache Speed:' $processor.L3CacheSpeed -ForegroundColor Yellow
>> Write-Host Strength ... `
>> `n'Number of Cores:' $processor.NumberOfCores `
>> `n'Number of Logical Processors:' $processor.NumberOfLogicalProcessors `
>> `n'Name:  $processor.Name -ForegroundColor Magenta
>> Write-Host Agility ... `
>> `n"Address Width: `t`t`t`t" $processor.AddressWidth -ForegroundColor Cyan
>>
Strength evaluation for LocalHost
Speed ...  2834
L2 Cache Size: 6144
L2 Cache Speed: 2000
L3 Cache Size: N/A
L3 Cache Speed: N/A
Strength ...
Number of Cores: 4
Number of Logical Processors: 4
Name:                Intel(R) Core(TM)2 Quad CPU    Q9550  @ 2.83GHz
Agility ...
Address Width: 64
[↓] [vPodans]

По всей видимости оно получилось как и требовалось.

Advanced Division

И тут нас снова ждут соревнования. Здесь нам потребуется файл LongJump_Adv2.xls из Competitors Pack. Файл содержит данные об участниках прыжков в длину и результаты их 3-х попыток.

Задача:

  • На основании результатов 3-х попыток в колонку Result записать лучший результат из 3-х попыток
  • На основании результатов третей попытки для каждого участника, выбрать лучший результат из них и вывести на экран
  • Сравнить лучший результат из 3-х попыток для каждого участника с их средним результатом в сезоне. Такой графы я не нашёл, есть только лучший результат в сезоне. Вот с ним я и сравнивал. Если прыгун превзошёл свой личный рекорд сезона, то в графу Exceed,Achieve,Under Perform вписать Exceed. Если повторил, то Achieve или Under Perform, если лучший результат сегодня был хуже результата по сезону.
  • Отсортировать всю таблицу по графе Exceed,Achieve,Under Perform именно в таком порядке. Т.е. сперва идут те, кто улучшил свой показатель, потом – кто повторил и в самом конце те, кто не смог повторить свой результат в сезоне. И сохранить в файл с таким же именем.

Решение:

Вася Гусев решил окончательно сломать всем мозг разбором XLS в CSV, обработать его и собрать обратно в CSV – тиснуть сюда. Когда я это увидел – стало как-то не очень хорошо. Я решил работать прямо с XLS. И вот что у меня получилось:

# массив, который будет содержать результаты последней попытки прыжков, на основании
# которых нужно вывести лучший результат
$lastattempt = @()
# создаём COM объект и прочую рутину.
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
$excel.Workbooks.Open('C:\Users\vPodans\LongJump_Adv2.xls') | Out-Null
# у нас есть известное кол-во участников - 18. 19-я строка - это заголовки.
# поэтому я исходя из этого решил работать с колонкой Result (8-я по счёту). Т.к.
# некоторые попытки были провалены и в таблице стояли крестики. Чтобы вручную не парсить
# это всё, я в ячейку воткнул экселовскую формулу MAX, которая всё за меня сделает.
2..19 | %{$excel.Cells.Item($_,8).Value2 = "=max(e$_`:g$_)"
    # заодно в $lastattempt запишем результат последней попытки для текущего прыгуна
    $lastattempt += $excel.Cells.Item($_,7).Value2
    # сравниваем лучший результат за сегодня с результатом за сезон
    if ($excel.Cells.Item($_,8).Value2 -lt $excel.Cells.Item($_,4).Value2) {
    # и в соответствующую графу пишем результат
        $excel.Cells.Item($_,9).Value2 = "Under Perform"
    # вот тут пришлось использовать читы. Я не очень силён в custom sort в экселе, поэтому
    # рядышком я для каждого статуса Exceed/Achieve/.. я приписываю число. Вот по этому числу
    # я потом буду сортировать таблицу
        $excel.Cells.Item($_,10).Value2 = "3"
    } elseif ($excel.Cells.Item($_,8).Value2 -eq $excel.Cells.Item($_,4).Value2) {
        $excel.Cells.Item($_,9).Value2 = "Achieve"
        $excel.Cells.Item($_,10).Value2 = "2"
    } else {
        $excel.Cells.Item($_,9).Value2 = "Exceed"
        $excel.Cells.Item($_,10).Value2 = "1"
    }
}
# выбираем из LastAttempt лучший результат, попутно заменяя крестики на нолики (лол) и выводя лучший результат
$lastattempt | %{if ($_ -eq "x") {$_ = 0};$_} | sort | select -last 1
# выбираем диапазон изменения таблицы при сортировке. Заголовки не трогаем, поэтому начинаем с 2
$selection = $excel.Range("a2:j19")
# указываем колонку, по которой будем сортировать
$range = $excel.Range("j2:j19")
# сортируем
[void]$selection.Sort($range,"1")
# удаляем читерские числа, которые использовались для сортировки.
2..19 | %{$excel.Cells.Item($_,10).Value2 = ""}
# готово.
$excel.Save()
$excel.Quit()

Не скажу, что получилось коротко и идеально, но задачу вполне решает.