Posts on this page:
И оно свершилось! Хотя официально Scripting Games начинаются только 15-го июня, но уже со вчерашнего дня стали известны уже 2 задания. Для начала немного информации, что и как:
В принципе, вы можете решать задания как угодно, т.к. засчитываются все, которые отвечают условиям задания.
Итак, Event1 и оба дивизиона:
Из Competitors Pack нам потребуется файл 100 Meter Event.txt
Задача:
Решение:
Побегав курсором по файлу я обнаружил тот факт, что разделителем между столбцом Name и Country является табулятор ([Tab]), а между Country и Time стоит один пробел во второй строке, а в остальных строках стоит [Tab]. Следовательно, варианты использования командлетов с параметром –Delimeter не прокатят и нужно будет разбирать всё регулярными выражениями. Первый вопрос наталкивает на необходимость чтения файла не через Get-Content, а через [system.io.file]::ReadAllText(). Но я не вижу особого криминала в использовании родного для PowerShell командлета Get-Content. Это будет несложно. Основная проблема в том, как составить регулярное выражение. Я решил разобрать имя на First Name и LastName (т.к. правильней, всё же, будет, когда сначала идёт имя, а потом фамилия), далее выбрать Country от табуляции до первого числа. Причём, тут потребуется каждую часть сделать именованной (named capture). Если открыть PowerShell In Action на 111 странице, то там можно найти описание, как делать named captures. У меня регулярное выражение получилось вот такое:
^(?<ln>\w+)..(?<fn>.*)\t(?<country>.+)(?<time>\d\.\d+)
Что делает это выражение:
Давайте проверим его:
[↓] [vPodans] $file = gc '.\100 Meter Event.txt' [↓] [vPodans] $file[1] -match "^(?<ln>\w+)..(?<fn>.*)\t(?<country>.+)(?<time>\d\.\d+)" True [↓] [vPodans] $matches Name Value ---- ----- country Australia ln Aaberg fn Jesper time 8.57 0 Aaberg, Jesper Australia 8.57 [↓] [vPodans] $file[11] -match "^(?<ln>\w+)..(?<fn>.*)\t(?<country>.+)(?<time>\d\.\d+)" True [↓] [vPodans] $matches Name Value ---- ----- country Japan ln Hansen fn Anne Grethe time 8.85 0 Hansen, Anne Grethe Japan 8.85 [↓] [vPodans]
и теперь соберём объект с нужными свойствами и отправим его на выход. На выходе отсортируем объекты по параметру Time и выберем первые 3 объекта:
gc "100 Meter Event.txt" | ?{$_ -match "^(?<ln>\w+)..(?<fn>.*)\t(?<country>.+)(?<time>\d\.\d+)"} |%{ $obj = "" | Select @{n='Name';e={$matches.fn + " " + $matches.ln}}, @{n='Country';e={$matches.country}},@{n='Time';e={$matches.time}} $obj } | sort time | select -First 3 | ft -AutoSize
и вот вывод:
решил ещё отформатировать в Format-Table с ключом –AutoSize для красоты. Признаюсь, что это задание меня сильно озадачило. Для меня оно оказалось очень непростым (такие дела).
Для этой задачи нам потребуется файл Personal Information Cards_ADV1.txt из Competitors Pack.
Задача:
Решение:
В файле много пустых строк, но это не проблема. Итак, one-liner решение:
gc "Personal Information Cards_ADV1.txt" | ?{$_.trim().length -ne 0} | sort length | select -First 3
[↓] [vPodans] gc "Personal Information Cards_ADV1.txt" | ?{$_.trim().length -ne 0} | select –First 3 PPID Claims Street [↓] [vPodans]
Странно, что в Advanced Division получилось такое простое задание.
Работая с функциями в PowerShell можно столкнуться с одной особенностью – в качестве передачи аргументов в функции или скрипты вы можете использовать почти всё, кроме ключей (данных типа Switch). Их передавать можно, но тут есть одна особенность. Обычно это ощущается, когда вы работаете с командлетами. Возьмём простой пример:
function Test ([string[]]$Path, [String]$Filter, [switch]$Force) { Write-Host '$Path is:' $Path Write-Host '$Filter is:' $Filter Write-Host '$Force is:' $Force }
и вызовем эту функцию:
[↓] [vPodans] function Test ([string[]]$Path, [String]$Filter, [switch]$Force) { >> Write-Host '$Path is:' $Path >> Write-Host '$Filter is:' $Filter >> Write-Host '$Force is:' $Force >> } >> [↓] [vPodans] Test C:\ * -force $Path is: C:\ $Filter is: * $Force is: True [↓] [vPodans]
В принципе, всё как и ожидалось. Но если внимательно посмотреть на последний аргумент, то мы увидим лишь True, т.е. увидим факт, что ключ Force был передан. Однако, PowerShell не умеет подставять (биндить) переменную $Force (равно как и другие переменные) как именованный параметр в другую команду. Чтобы в этом убедиться, мы попробуем сымитировать нашу функцию как командлет Get-ChildItem:
[↓] [vPodans] function Test ([string[]]$Path, [String]$Filter, [switch]$Force) { >> Get-ChildItem $Path $Filter $Force >> } >> [↓] [vPodans] Test C:\ * -Force Get-ChildItem : A positional parameter cannot be found that accepts argument 'True'. At line:2 char:14 + Get-ChildItem <<<< $Path $Filter $Force + CategoryInfo : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand [↓] [vPodans]
Как видно, командлет Get-ChildItem не смог сопоставить последний аргумент ни с одним из своих параметров. Т.е. по факту выполнилась следующая строка:
Get-ChildItem -Path C:\ -Filter * True
PowerShell не смог сказать командлету, что мы указали ключ Force и хотим именно его передать в командлет. По факту в этом коде Get-ChildItem не знал, какие параметры ему были переданы и подставлял их на основе номера позиции параметра. А т.к. у Get-ChildItem нету параметра с порядковым номером 3 (с номером 1 идёт Path или LiteralPath, а с номером 2 идёт Filter. Остальные параметры именованные), то мы получили ошибку. Но всё же, как выкручиваться из этой ситуации? Вы можете как угодно пытаться подставить аргументы, но ничего не выйдет. Для этих целей в PowerShell V2 появилась специальная переменная - $PSBoundParameters. Эта переменная по сути представляет собой хэш-таблицу:
[↓] [vPodans] function Test ([string]$Path, [String]$Filter, [switch]$Force) { >> $PSBoundParameters >> } >> [↓] [vPodans] Test C:\ * -Force Key Value --- ----- Force True Path C:\ Filter * [↓] [vPodans]
В отличии от первого примера переменная $PSBoundParameters содержит не только значения переменных, но и их имена (в перовм примере я вручную дописывал имена переменных), которые используются в качестве именованных параметров. Т.е. при подстановке аргументов в команду, она сначала выбирает имя переменной в качестве именованного параметра и значение переменной подставляет в качестве аргумента этого параметра. Синтаксис использования этой переменной очень прост:
function Name ($arg1, $arg2, $arg3 ... $argN) {
Command @PSBoundParameters
}
и в результате будет исполняться вот такая команда:
Command –arg1 <значение $arg1> –arg2 <значение $arg2> –arg3 <значение $arg3> … –argN <значение $argN>
Т.е. будут подставляться именованные параметры и значения переменных соответствующих аргументов. Давайте проверим, как это подействует на наш пример с Get-ChildItem:
function Test ([string]$Path, [String]$Filter, [switch]$Force) { Get-ChildItem $PSBoundParameters }
[↓] [vPodans] function Test ([string]$Path, [String]$Filter, [switch]$Force) { >> Get-ChildItem @PSBoundParameters >> } >> [↓] [vPodans] Test C:\ * -Force Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d--hs 10.07.2007. 19:44 $Recycle.Bin d--hs 09.03.2008. 17:53 Boot d---- 23.11.2008. 19:41 inetpub d-rh- 26.06.2007. 22:27 MSOCache d---- 09.03.2008. 17:41 PerfLogs <...>
И вы можете видеть, что у нас всё получилось в наилучшем виде! В сравнении с предыдущим примером фактически выполнилась следующая команда:
Get-ChildItem -Path C:\ -Filter * -Force
Для формирования аргументов для командлетов в функциях (так называемые wrapped cmdlets) это самый красивый и идеальный вариант. Если вы захотите изменить логику стандартных командлетов или добавить в них свой функционал, то $PSBoundParamters сделает за вас очень много лишней работы. Но это не единственное полезное применение для этой переменной. Она так же позволяет сократить возможность ошибки при вызове функции внутри скрипта или другой функции, которая принимает те же аргументы. Давайте посмотрим ещё один пример:
function Test ([string[]]$Path, [String]$Filter, [switch]$Force) { Write-Host '$Path in Test is:' $Path Write-Host '$Filter in Test is:' $Filter Write-Host '$Force in Test is:' $Force Write-Host -------------------------------- function Test2 ([switch]$Force, [string[]]$Path, [String]$Filter) {
Write-Host '$Path in Test2 is:' $Path Write-Host '$Filter in Test2 is:' $Filter Write-Host '$Force in Test2 is:' $Force } Test2 @PSBoundParameters }
Что мы делаем: мы создали функцию Test, которая принимает набор аргументов. Внутри этой функции есть другая функция Test2, которая принимает те же аргументы. Далее из функции Test вызываем функцию Test2 и с помощью $PSBoundParameters передаём в неё аргументы. Обратите внимание, что в функции Test2 я изменил порядок аргументов. Это сделано для того, чтобы показать, что $PSBoundParamters отсортирует наши аргументы. А теперь внимание на экран:
[↓] [vPodans] function Test ([string[]]$Path, [String]$Filter, [switch]$Force) { >> Write-Host '$Path in Test is:' $Path >> Write-Host '$Filter in Test is:' $Filter >> Write-Host '$Force in Test is:' $Force >> Write-Host -------------------------------- >> function Test2 ([switch]$Force, [string[]]$Path, [String]$Filter) { >> Write-Host '$Path in Test2 is:' $Path >> Write-Host '$Filter in Test2 is:' $Filter >> Write-Host '$Force in Test2 is:' $Force >> } >> Test2 @PSBoundParameters >> } >> [↓] [vPodans] Test C:\ * -Force $Path in Test is: C:\ $Filter in Test is: * $Force in Test is: True -------------------------------- $Path in Test2 is: C:\ $Filter in Test2 is: * $Force in Test2 is: True [↓] [vPodans]
И смотрите, что у нас получилось. А у нас получилось, что функция Test2 получила тот же набор аргументов, причём они были подставлены в правильном соответствии. Фактически строка Test2 @PSBoundParameters была преобразована в:
Test2 -Path $Path -Filter $Filter -Force $true
Т.е. в вариант, который мы вынуждены использовать в PowerShell 1.0. Плюс, мы имеем возможность подставлять позиционно ключи (объекты типа Switch), что есть очень позитивно.
Hal Rottenberg и Shay Levy сегодня собрали список блогов всех действующих MVP по PowerShell. Думается, что это будет весьма полезный для многих список, в котором любители PowerShell могут массу наиполезнейшей информации. Итак, вот список:
MVP Name | Blog Name | Blog language |
/\/\o\/\/ | ThePowerShellGuy | English |
Arnaud Petitjean | PowerShell Scripting | French |
Brandon Shell | BS on PoSH | English |
Charlie Russel | x(perts)64 | English |
Daisuke Mutaguchi | Scripting Weblog | Japanese |
Dmitry Sotnikov | PowerShell and beyond | English |
Don Jones | Concentrated Technology | English |
Doug Finke | Development in a Blink | English |
Gu Huajun | ghjconan's blog | Chinese |
Guy Thomas | English | |
Hal Rottenberg | TechProsaic | English |
Hiroki Takahashi | HIRO’s.NET | Japanese |
Hiroshi Yoshioka | PowerShell Memo | Japanese |
Jeffrey Hicks | Scripting Blog and More | English |
Karl Prosser | Live PowerShell | English |
Keith Hill | Keith Hill’s Blog | English |
Kirk Munro | Poshoholic | English |
Marco Shaw | Get-PowershellBlog | English |
Max Trinidad | Florida PowerShell User Group | English |
Oisin Grehan | Nivot Ink | English |
Richard Siddaway | Richard Siddaway’s Weblog | English |
Shay Levy | $cript Fanatic | English |
Sherif Talaat | The Arabian PowerShell | Arabic |
Tobias Weltner | Dreaming in PowerShell | English |
Vadims Podans | PowerShell Powered | Russian |
Vasily Gusev | PowerShell и другие скрипты | Russian |
Vinicius Canto | e a arte de criar scripts | Portuguese |
Ying Li | PowerShell & System Center | English |
Удачи! © One
Иногда замечаю, что некоторые скриптописатели получают “поломанный” конвейер, когда данные из одной команды вышли, но никуда не пришли. Возьмём простой пример:
[↓] [vPodans] foreach ($n in 1..3) {$n} 1 2 3 [↓] [vPodans]
Тут всё просто, циклом foreach перебираются данные и выводятся на экран. Мы привыкли, что всё, что выводится на экран можно передать дальше на конвейер. В принципе, это правильно, за исключением ряда случаев, когда это не работает. Чтобы убедиться в этом – передадим вывод этой команды через конвейер на Set-Content:
[↓] [vPodans] foreach ($n in 1..3) {$n} 1 2 3 [↓] [vPodans] foreach ($n in 1..3) {$n} | Set-Content file.txt An empty pipe element is not permitted. At line:1 char:28 + foreach ($n in 1..3) {$n} | <<<< Set-Content file.txt + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : EmptyPipeElement [↓] [vPodans]
и мы получаем ошибку, что у нас пустой конвейер. Если написать простой проверочный фильтр:
filter Test-Input {'current $_ is: ' + $_}
и проверить, что у нас приходит с конвейера в этот фильтр, то вы получите такую же ошибку и можете долго гадать, почему так, на экране данные есть, а в конвейер ничего не поступает. Причиной этому является то, что flow control (не знаю, как это на русский первести) конструкции не транслируют свой вывод в конвейер и вот список этих конструкций:
Чтобы при использовании этих конструкций вывод транслировался на конвейер их нужно заключить в подвыражение – $( ):
[↓] [vPodans] $(foreach ($n in 1..3) {$n}) | Set-Content file.txt [↓] [vPodans] gc file.txt 1 2 3 [↓] [vPodans] $(foreach ($n in 1..3) {$n}) | Test-Input current $_ is: 1 current $_ is: 2 current $_ is: 3 [↓] [vPodans]
я заключил цикл Foreach в подвыражение и теперь данные стали поступать на конвейер. Это хорошо видно по выводу фильтра Test-Input, который приведён выше. Вот таким нехитрым способом мы решили проблему пустых конвейеров :-)
Недавно на форуме SysFaq.ru была занятная тема про порядок применения групповых политик в домене. В общем смысле там вопрос сводился к приоритету политик, что настроенный параметр в доменной политике будет иметь приоритет над тем же параметром в локальной политике и работает принцип LSDOU (Local, Site, Domain, OU). Но если говорить по SRP, то здесь есть свои нюансы.
Если политика SRP определена в нескольких политиках, то результирующая политика не будет состоять из значений последней применившейся политики. Все значения исключений из всех политик будут сложены в одну большую политику с возможными конфликтами. Важно отметить, что в вычислении результирующей политики порядок их применения не имеет никакого значения. Когда вы смотрите в RSOP, то видите такую вещь:
fig.1.
Т.е. видно, какая политика выиграла. В случае с SRP, вы этого не увидите:
fig.2.
Когда вы получите набор правил из всех политик, то вполне вероятны конфликтные ситуации, когда в одной политике правило разрешает запуск чего-то, а в другой политике запрещается, то финальная политика определяется по своим особым законам. Причём, сложности добавляет тот факт, что внутри порядки разные. Например, порядок разбора правил путей отличается от порядка разбора всех остальных типов правил. Поэтому я решил немного детальней осветить этот вопрос, чтобы не было никакой путаницы. Я ещё в журнальной статье (На страже безопасности – Software Restriction Policies) отмечал про порядок применения типов правил. Однако, формат журнала не позволял детально рассмотреть этот момент, поэтому я его раскрываю здесь.
Итак, когда на клиентский компьютер применилось несколько политик со своими правилами, то они сортируются по конфликтным парам. Конфликтную пару могут составить 2 одинаковых правила (например, по сертификату или хешу), но с разными уровняеми (Unrestricted, Disallowed). Если для правила не нашлось конфликтной пары, то оно считается единственным правилом в паре и в итоге оно будет результирующим. При этом все пары сортируются и проверяются в строгом порядке:
Для первых трёх типов на каждый объект может быть задана одна пара правил (не может быть для одного файла 2 разных хеша, поэтому для него существует только один хеш и для этого хеша может быть 2 уровня – Unrestricted/Disallowed). И для первых трёх типов правил работает правило First Matching. При попытке запуска файла сперва проверяется запрет по правилу сертификата. Если он есть, то дальнейшая проверка правил обрывается и на основе first matching доступ прекращается. Если же запрета нету, то проверяется разрешение на основе сертификата. Если разрешение есть, то опять же на основе first matching доступ к файлу разрешается и остальные правила не проверяются. Если же правила сертификатов для объекта не обнаружено, то проверка переходит к правилам хешей. Та же самая ситуация повторяется и с хешами и правилами сетевой зоны. Если ничего из этого не соответствует объекту, то процесс переходит к проверке правил путей.
В правилах пути существует свой порядок сортировки правил:
Здесь так же правила разбиваются на пары. Т.е. для каждой точки пути подбирается такое же правило, но с другим уровнем Unrestrited/Disallowed. Как можно заметить, здесь меняется порядок проверки запретов и разрешений. Если в первых трёх типах правил первыми проверялись запреты, то в правилах путей всё наоборот – сначала обрабатываются разрешения и только потом запреты. Это обусловлено тем, что для правил путей нету правила First Matching, а проверяются абсолютно все правила. При этом, как видно из описания, сначала проверяются более общие правила с бОльшей площадью охвата (как весь диск C:\). И вот так проверяются все правила путей и результирующим правилом для объекта станет то, которое проверилось самым последним, которое будет самым точным из всех правил, под которое подпадает проверяемый объект. Безусловно, если есть пара, которая одновременно разрешает и запрещает запуск по полному имени файла, то последним проверится запрет и доступ будет запрещён. В этом смысле так же работает правило, что одинаковый запрет имеет приоритет над таким же разрешением. Если в исключениях не нашлось ни одного правила, под которое смог бы подпасть объект, тогда решение о запуске будет приниматься на основе Default Level.
Примечание: при проверке результирующей суммы в RSOP.MSC на клиентах Windows Vista SP1 и выше вы можете попасть на одну засаду. Дело в том, что новая консоль RSOP.MSC теперь показывает не всё. В разрезе результирующей политики вы не увидите правил сертификатов! Т.е. они по факту есть и работают (соответствующие сертификаты размещаются в контейнерах Trusted/Untrusted Publishers в CertStore), но в этой консоли их не будет. Почему так – я не знаю, но вам следует принимать во внимание этот факт.
Примечание: хочу замтетить, что порядок применения политик SRP влияет только на Default level, Enfocrement, Designated Files Types и секцию Trusted Publishers. Для Additional Rules порядок применения политик не имеет значения.