Posts on this page:
Бег на 110 метров с барьерами.
Задача:
Решение:
Всё копировать не буду, а только приведу уже готовый скрипт. Сам текст скрипта можно взять тут: 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 ярлыка и первый будет вести именно на файл самого скрипта.
и снова задача на парсинг текста. Потребуется файл network trace_adv6.txt из Competitors pack.
Задача:
Решение:
Самая первая задача, которая перед нами встаёт – создание регулярного выражения. Выражение у меня получилось вот такое:
^\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, но мне нравится этот ключ :-) вобщем, об этой фиче не забывайте.
задача на работу с реестром.
Задача:
Решение:
Ключи и значения реестра для этой задачи можно найти тут: 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]
как бы ничего сложного.
работа с тэгами файлов. Потребуются файлы TechEd1.JPG, TechEd2.JPG и TechEd3.JPG из Competitors Pack.
Задача:
Решение:
Задача не такая и сложная, на самом деле, как кажется. Для начала нам потребуется класс 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]
Вобщем, как видите, тут тоже ничего сверхсложного нету.
Прыжки с шестом.
Потребуется файл HighJumperDatabase.mdb из Competitors Pack.
Задача:
Решение:
Никогда не приходилось работать с 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.
потребуется файл High Jump Stats_Adv4.txt из Competitors Pack.
В файле перечислены имена прыгунов с шестом и через запятую перечислены высОты планки.
Задача:
Решение:
Т.к. я графики тоже никогда не рисовал, поэтому тоже пришлось обратиться к гуглу. И вышло примерно такое:
# переименовываем 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"
3-е задание на парсинг текста.
Потребуется файл Shot Put.txt из Competitors Pack.
Задача:
Решение:
Если внимательно посмотреть на файл, то в нём можно найти одну уникальную последовательность - `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'
потребуется файл Wordlist_ADV3.txt из Competitors Pack.
Задача:
Решение:
В принципе, тут есть только одно простое решение (считайте, что нагло стырено у Васи):
gc .\Wordlist_ADV3.txt | ?{$_ -replace '[^AEIOUY]' -match '^(.)\1*$'} > 'Wordlist_ADV3_new.txt'
суть решения заключается в том, чтобы из каждого слова убрать все согласные и проверить, что в слове используется только одна гласная 1 или более раз. Этот регексп описан в PowerShell Cookbook на странице 494.
Тут очень простое задание из серии фаллометрии :-)
Задача:
Решение:
Тут нам потребуется 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 ` `nL2 Cache Size: $processor.L2CacheSize ` `nL2 Cache Speed: $processor.L2CacheSpeed ` `nL3 Cache Size: $processor.L3CacheSize ` `nL3 Cache Speed: $processor.L3CacheSpeed -ForegroundColor Yellow Write-Host Strength ... ` `nNumber of Cores: $processor.NumberOfCores ` `nNumber of Logical Processors: $processor.NumberOfLogicalProcessors ` `nName: ```````````` $processor.Name -ForegroundColor Magenta Write-Host Agility ... ` `nAddress 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]
По всей видимости оно получилось как и требовалось.
И тут нас снова ждут соревнования. Здесь нам потребуется файл LongJump_Adv2.xls из Competitors Pack. Файл содержит данные об участниках прыжков в длину и результаты их 3-х попыток.
Задача:
Решение:
Вася Гусев решил окончательно сломать всем мозг разбором 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()
Не скажу, что получилось коротко и идеально, но задачу вполне решает.