Интересные примеры на PowerShell. Powershell примеры foreach


Foreach — из книги PowerShell in depth / Хабр

Глава 19.3. В ней описывается конструкция Foreach, как ее применять.

Эта конструкция имеет те же цели что и командлет ForEach-Object. Командлет ForEach-Object имеет алиас ForEach, который легко спутать с оператором ForEach… потому что они имеют абсолютно одинаковые имена. PowerShell смотрит на контекст чтобы выяснить, какой же Foreach применяется сейчас. Вот пример того, как оператор, и командлет делают одно и тоже

Get-Service –name B* | ForEach { $_.Pause() } $services = Get-Service –name B* ForEach ($service in $services) { $service.Pause() } Разберем как работает эта оператор Foreach, в нем есть две переменные в скобках, разделенные ключевым словом in. Вторая переменная, как ожидается содержит один или несколько объектов с которыми мы хотим что то сделать. Первая переменная для внутреннего использования, она будет содержать по очереди в каждом проходе объект из второй переменной. Если вы писали на VBScript то такого рода вещи должны выглядеть для вас знакомыми.

Обычная практика именовать вторую переменную во множественном числе, а первую в единственном. Это не требуется соглашением или стандартом, хотя вы можете написать Foreach( $Fred in $Rocvill ) при условии что в $Rockvill содержатся объекты, PowerShell будет рад обработать это. Но придерживайтесь осознанного именования переменных, тогда вам придется гораздо меньше запоминать.

PowerShell автоматически принимает по одному объекту из второй переменной и помещает его в первый на каждом проходе цикла. Внутри конструкции можно использовать первую переменную для того чтобы делать что то с объектом, например вы можете вызвать метод Pause этого объекта. Не используйте $_ (или PSItem) в операторе, как вы это делаете в командлете.

Иногда, вы можете быть не уверены какую конструкцию использовать — оператор или командлет. Теоретически передача по конвееру на Foreach-object может использовать меньше памяти в некоторых ситуациях. По нашим наблюдениям командлет работает медленнее с большими наборами объектов. Если у вас есть сложная обработка в конвеере, особенно если ведется обработка оператором Foreach внутри командлета Foreach лучше использовать полное название чтобы однозначно определить что именно исполльзуется.

Вам также нужно быть осторожнее если вы хотите сделать передачу по конвееру на другой командлет или функцию. Пример

PS C:\> foreach ($service in $services) { >> $service | select Name,DisplayName,Status >> } | Sort Status >> An empty pipe element is not allowed. At line:3 char:4 + } | <<<< Sort Status + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : EmptyPipeElement PowerShell выдал ошибку, потому что нечего передать дальше по конвееру на Sort, но этот пример будет работать:PS C:\> $services | foreach { >> $_ | select Name,DisplayName,Status >> } | Sort Status >> Name DisplayName Status ---- ----------- ------ Browser Computer Browser Stopped BDESVC BitLocker Drive Encrypt... Stopped bthserv Bluetooth Support Service Running BFE Base Filtering Engine Running BITS Background Intelligent ... Running Другим фактором является нужно ли вам будет использовать коллекцию объектов еще раз, если вам понадобится дальше коллекция то лучше использовать оператор, чтобы не получать данные снова. Последний момент состоит в том что многие скрипты которые вы найдете в интернете являются на самом деле конвертацией скриптов VBScript, в нем постоянно приходилось перебирать коллекции объектов. Поэтому всегда стоит остановиться и подумать секунду чтобы определить наилучший подход и надо ли перебирать коллекцию вообще.

Наш совет — не используйте перебор если есть возможность этого не делать. Для примера перепишем наш код приведенный ранее по другому:

Get-Service –name B* | Suspend-Service и пример сортировки будет намного лучше выглядеть если написать его так:Get-Service b* | Sort Status | select Name,DisplayName,Status Если вам не нужно для чего то перебирать все объекты не делайте этого. Использование Foreach командлета либо оператора иногда является признаком того вы делаете то что не следует делать. Это конечно верно не во всех случаях, но задумайтесь может ли PowerShell сделать часть работы за вас. Не зацикливайтесь на этом вопросе, многие командлеты просто не принимают выходные данные из конвеера на параметры которые вам могут быть необходимы, в таком случае использование Foreach становится необходимостью. Важнее закончить работу чем отслеживать правильно или неправильно вы что то написали.вставка переводчика имеется в виду способность пошика связывать между собой параметры объектов на конвеере по именам параметров. Если есть вероятность что пош не сможет однозначно идентифицировать параметр объекта в процессе «parameter binding» то придется перебирать объекты по одному. Например WMI. Общая рекомендфция — используйте конвеерную обработку, цикл как правило, прерывает конвеер, а иногда приводит к ненужным итерациям. Например эффективнее сделать Select а затем обработку, чем if внутри Foreach и обработку Хороший момент чтобы напомнить вам о скобках. Мы приврали когда сказали что оператору Foreach требуется две переменные. С технической точки зрения для этого нужна только одна переменная. Вторая должна содержать коллекцию объектов, которые могут находится либо в переменной как в наших примерах до этого, либо могут быть результатом выражения в скобках, например:foreach ($service in (Get-Service –name B*)) { $service.pause() } Эта версия труднее читается, но является абсолютно законной, устраняя необходимость хранить промежуточные результаты в переменной. Внутренние скобки вычисляются в первую очередь и производят коллекцию объектов которая передается дальше.

habr.com

about_ForEach

Содержит описание команды языка, позволяющей перебирать все элементы в коллекции.

Оператор Foreach (называемый также циклом Foreach) является языковой конструкцией для пошагового перемещения (итерации) по последовательности значений в коллекции элементов.

Самым простым и наиболее часто используемым типом коллекции, по которой производится перемещение, является массив. Обычно в цикле Foreach одна или несколько команд выполняются применительно к каждому элементу массива.

Синтаксис

Ниже показан синтаксис оператора ForEach.

foreach ($<item> in $<collection>){<statement list>}

Упрощенный синтаксис

Начиная с версии Windows PowerShell® 3.0 синтаксис с ключевыми словами языка, например Where и ForEach, был упрощен. Операторы сравнения, которые применяются к элементам коллекции, рассматриваются как параметры. К элементам коллекции можно применять метод, не включая его в блок сценария и не добавляя автоматическую переменную «$_.». Рассмотрим следующие два примера:

dir cert:\ -Recurse | foreach GetKeyAlgorithm dir cert:\ -Recurse | foreach {$_.GetKeyAlgorithm()}

Хотя обе команды работают, первая возвращает результаты без использования блока сценария или автоматической переменной «$_.». Метод GetKeyAlgorithm рассматривается как параметр оператора ForEach. Первая команда возвращает те же результаты, но без ошибок, так как упрощенный синтаксис не пытается вернуть результаты для элементов, к которым не был применен указанный аргумент.

В этом примере свойство Description командлета Get-Process передается в качестве аргумента параметра оператора ForEach. Результаты представляют собой описания активных процессов.

Get-Process | ForEach Description

Оператор Foreach за пределами конвейера команд

В заключаемой в круглые скобки части оператора Foreach указываются переменная и коллекция для перебора. При выполнении цикла Foreach среда Windows PowerShell автоматически создает переменную ($<элемент>). Перед каждой итерацией в цикле переменной присваивается значение в коллекции. Блок после оператора Foreach {<список_операторов>} содержит набор команд, выполняемых применительно к каждому элементу коллекции.

Примеры

Например, цикл Foreach в приведенном ниже примере отображает значения в массиве $letterArray.

$letterArray = "a","b","c","d" foreach ($letter in $letterArray) { Write-Host $letter }

В этом примере создается массив $letterArray, который затем инициализируется строковыми значениями «a», «b», «c» и «d». При первом выполнении оператора Foreach переменная $letter устанавливается равной первому элементу в массиве $letterArray («a»). Затем буква «a» отображается с помощью командлета Write-Host. При следующей итерации цикла переменной $letter присваивается значение «b» и т. д. После того как цикл Foreach отобразит букву «d», Windows PowerShell выходит из цикла.

Чтобы оператор Foreach выполнялся как команда в командной строке Windows PowerShell, он должен быть представлен в одной строке целиком. Оператор Foreach не обязательно должен быть представлен в одной строке целиком, если команда помещена в файл сценария PS1.

Операторы Foreach могут также использоваться вместе с командлетами, возвращающими коллекции элементов. В приведенном ниже примере оператор Foreach выполняет перебор элементов списка, возвращаемого командлетом Get-ChildItem.

foreach ($file in Get-ChildItem) { Write-Host $file }

Пример можно усовершенствовать с помощью оператора If для ограничения возвращаемых результатов. В примере ниже оператор Foreach выполняет те же операции в цикле, что и в предыдущем примере, но здесь добавлена инструкция If, ограничивающая результаты файлами, размер которых превышает 100 килобайт (КБ).

foreach ($file in Get-ChildItem) { if ($file.length -gt 100KB) { Write-Host $file } }

В этом примере цикл Foreach использует свойство переменной $file для выполнения операции сравнения ($file.length -gt 100KB). Переменная $file содержит все свойства в объекте, возвращаемом командлетом Get-ChildItem. Поэтому может возвращаться не только имя файла. В следующем примере Windows PowerShell внутри списка операторов возвращает длину и время последнего обращения.

foreach ($file in Get-ChildItem) { if ($file.length -gt 100KB) { Write-Host $file Write-Host $file.length Write-Host $file.lastaccesstime } }

В этом примере в списке операторов не обязательно выполнять только одну команду.

Кроме того, можно использовать переменную вне цикла Foreach и увеличивать ее значение внутри цикла. В примере ниже подсчитываются файлы, размер которых превышает 100 КБ.

$i = 0 foreach ($file in Get-ChildItem) { if ($file.length -gt 100KB) { Write-Host $file "file size:" ($file.length / 1024).ToString("F0") KB $i = $i + 1 } } if ($i -ne 0) { Write-Host Write-Host $i " file(s) over 100 KB in the current directory."} else { Write-Host "No files greater than 100 KB in the current directory." }

В предыдущем примере переменной $i присваивается значение 0 вне цикла, а увеличение значения происходит внутри цикла для каждого найденного файла размером больше 100 КБ. При выходе из цикла инструкция If вычисляет значение переменной $i для отображения количества всех файлов размером более 100 КБ. Либо выводится сообщение о том, что ни одного файла размером более 100 КБ не найдено.

Предыдущий пример также демонстрирует, как форматировать результаты для длины.

($file.length / 1024).ToString("F0")

Значение делится на 1024, чтобы показать результаты в килобайтах, а не в байтах. Полученное значение далее форматируется с помощью спецификатора формата с фиксированной запятой для удаления из результата дробной части. Значение 0 спецификатора формата указывает, что дробная часть отображаться не должна.

Оператор Foreach внутри конвейера команд

Когда оператор Foreach используется в конвейере команд, Windows PowerShell использует псевдоним foreach, вызывающий команду ForEach-Object. При использовании псевдонима foreach в конвейере команд не используется синтаксическая конструкция ($<элемент> in $<коллекция>), как это делается с оператором Foreach. Это является следствием того, что эти сведения предоставляет предыдущая команда в конвейере. Синтаксис псевдонима foreach, применяемого в конвейере команд, выглядит следующим образом:

<command> | foreach {<command_block>}

Например, цикл Foreach в следующем конвейере команд отображает процессы, рабочий набор (использование памяти) которых превышает 20 мегабайт (МБ).

Команда Get-Process получает имена всех процессов на компьютере. Псевдоним Foreach выполняет команды в блоке сценария для каждого процесса в последовательности.

Оператор IF выбирает процессы с рабочим набором (WS) больше 20 мегабайт. Командлет Write-Host записывает имя процесса и ставит после него двоеточие. Он делит значение рабочего набора, которое хранится в байтах, на 1 мегабайт, чтобы получить значение рабочего набора в мегабайтах. Затем он преобразует результат из типа double в строку. Значение выводится в виде числа с фиксированной запятой с нулем десятичных знаков (F0), за которым следует пробел (« ») и «МБ».

Write-Host "Processes with working sets greater than 20 MB." Get-Process | foreach { if ($_.WS -gt 20MB) { Write-Host $_.name ": " ($_.WS/1MB).ToString("F0") MB -Separator ""} }

Псевдоним foreach также поддерживает начальные, средние и конечные блоки команд. Начальный и конечный блоки команд выполняются один раз, а средний блок команд выполняется каждый раз, когда цикл Foreach перемещается к очередному элементу коллекции или массива.

Синтаксис псевдонима foreach, используемого в конвейере команд с начальным, средним и конечным блоками команд, выглядит следующим образом:

<command> | foreach {<beginning command_block>}{<middle command_block>}{<ending command_block>}

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

Get-ChildItem | foreach { $fileCount = $directoryCount = 0}{ if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}{ "$directoryCount directories and $fileCount files"}

Начальный блок создает и инициализирует две переменные со значением 0.

{$fileCount = $directoryCount = 0}

Средний блок проверяет, является ли возвращаемый командлетом Get-ChildItem элемент каталогом или файлом.

{if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}

Если возвращаемый элемент является каталогом, значение переменной $directoryCount увеличивается на 1. Если элемент не является каталогом, на 1 увеличивается значение переменной $fileCount. Конечный блок выполняется после того, как средний блок завершает цикл и возвращает результат операции.

{"$directoryCount directories and $fileCount files"}

С помощью структуры начального, среднего и конечного блоков команд и оператора конвейера можно переписать приведенный выше пример поиска файлов размером более 100 КБ следующим образом:

Get-ChildItem | foreach{ $i = 0}{ if ($_.length -gt 100KB) { Write-Host $_.name "file size:" ($_.length / 1024).ToString("F0") KB $i++ } }{ if ($i -ne 0) { Write-Host Write-Host "$i file(s) over 100 KB in the current directory." } else { Write-Host "No files greater than 100 KB in the current directory."} }

В приведенном ниже примере функции, которая возвращает функции, использующиеся в сценариях и модулях сценариев, демонстрируется, как использовать метод MoveNext (работающий аналогично «skip X» в цикле For) и свойство Current переменной $foreach в блоке сценария foreach даже при наличии необычных или неединообразных определений функций, имена которых объявлены в нескольких строках. Этот пример также работает при наличии комментариев в функциях, используемых в сценарии или модуле сценария.

function Get-FunctionPosition { [CmdletBinding()] [OutputType('FunctionPosition')] param( [Parameter(Position=0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [Alias('PSPath')] [System.String[]] $Path ) process { try { $filesToProcess = if ($_ -is [System.IO.FileSystemInfo]) { $_ } else { Get-Item -Path $Path } foreach ($item in $filesToProcess) { if ($item.PSIsContainer -or $item.Extension -notin @('.ps1','.psm1')) { continue } $tokens = $errors = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile($item.FullName,([REF]$tokens),([REF]$errors)) if ($errors) { Write-Warning "File '$($item.FullName)' has $($errors.Count) parser errors." } :tokenLoop foreach ($token in $tokens) { if ($token.Kind -ne 'Function') { continue } $position = $token.Extent.StartLineNumber do { if (-not $foreach.MoveNext()) { break tokenLoop } $token = $foreach.Current } until ($token.Kind -in @('Generic','Identifier')) $functionPosition = [pscustomobject]@{ Name = $token.Text LineNumber = $position Path = $item.FullName } Add-Member -InputObject $functionPosition -TypeName FunctionPosition -PassThru } } } catch { throw } } }

technet.microsoft.com

Расширяйте вашу работу с FOREACH – Русский блог команды разработки Powershell

Прошлым вечером я и Брюс Пайет (Bruce Payette) и я были проинтерьюированы на подкасте PowerScripting с Хэлом Роттенбергом (Hal Rottenberg) и Джонатаном Вольцом (Jonathan Walz). Это был взрыв! Множество людей подключились и мы были завалены вопросами и комментариями в окне чата. Было множество комментариев и обсуждений о Twitter. Я признался, что никогда ранее не использовал twitter.

Сегодня утром я получил письмо от Джэфри Хикса (Jeffery Hicks ) – он рекомендовал сайт под названием TweetGrid который позволяет "просматривать tweet-поток" без аккаунта в Twitter. (Если я имею аккаунт, я становлюсь Твитом (Twit)?) Он отправил мне ссылку на страницу с результатами поиска «PowerShell» и «CTP3».

Я не готов рекомендовать это, НО первым сообщением была ссылка на пост Хуго Питерса (Hugo Peeters) о скрипте, который добавляет информацию о размере RDM в VI-клиент с помощью PowerShell. Мне понравилось смотреть на скрипты других людей – это дало мне возможность взглянуть, что думают вокруг, помогло понять, какие примеры используются и дало мне идею о том, как развивать язык и саму платформу.

Хуго написал хороший скрипт – его очень легко читать и поддерживать. Но одна вещь обратила на себя мое внимание. Он пишет:

$VMs = Get-VM ForEach ($VM in $VMs)

Это очень хороший код –  традиционный путь использования цикла foreach. Но циклы foreach в PowerShell – это гораздо больше. Я обнаружил, что где бы я ни писал подобный код, я бы сейчас написал его так:

 

В PowerShell, вместо КОЛЛЕКЦИИ в выражении может быть ЛЮБОЕ ВЫРАЖЕНИЕ ИЛИ ОПЕРАТОР, КОТОРЫЕ СОЗДАЮТ КОЛЛЕКЦИЮ. Таким образом, вы можете использовать операторы в циклах foreach. У меня нет VMWARE, так что я не могу привести хорошие примеры с VM, но вот примеры того, что я имею в виду:

 

foreach ($p in Get-Process *ss) { $p.Name} # A cmdlet is a statement which generates a collection. Don't worry if it # only generates 1 value - PowerShell casts it to a collection foreach ($p in Get-Process |where {$_.handles -ge 500}) { $p.Name} # A pipeline is a statement as well foreach ($p in Get-Process |where {$_.handles -ge 500} | sort handles) { $p.Name} # There is no restrictions on what you do in your statement

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

foreach ($p in $($max=700; gps |where {$_.handles -le $max})) {$p.Name}

Вот почему я люблю такое использование foreach:

  1. Так проще читать и обслуживать.
  2. Это короче. Если код удобен для чтения, более короткий код обычно лучше. В этом случае меньше вещей, которые нужно отслеживать, и меньше вещей, которые могут пойти не так.
  3. Нет необходимости придумывать хорошее имя для переменной.
  4. Я счастлив от того, что вы можете делать это на PowerShell (не очень хорошая причина, но зато честно. 🙂 ).

Спасибо Хуго за хороший скрипт!

Спасибо Джефри за рекомендацию!

Спасибо за великолепный подкаст Хэлу и Джонатану!

Наслаждайтесь!

Джеффри Сновер (Jeffrey Snover) [MSFT] Windows Management Partner Architect Посетите английский блог команды  Windows PowerShell:    http://blogs.msdn.com/PowerShellПосетите Windows PowerShell ScriptCenter:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Перевод: Илья Лушников

blogs.technet.microsoft.com

about_Foreach

РАЗДЕЛ about_Foreach КРАТКОЕ ОПИСАНИЕ Описывает команду языка, позволяющую перебрать все элементы в коллекции. ПОЛНОЕ ОПИСАНИЕ Инструкция Foreach (называемая также циклом Foreach) является языковой конструкцией для пошагового перемещения (итерации) по последовательности значений в коллекции элементов. Самым простым и наиболее часто используемым типом коллекции, по которой производится перемещение, является массив. Обычно в цикле Foreach одна или несколько команд выполняются на каждом элементе массива. Синтаксис Ниже показан синтаксис инструкции Foreach: foreach ($<элемент> in $<коллекция>){<список_инструкций>} Инструкция Foreach за пределами конвейера команд В заключаемой в круглые скобки части инструкции Foreach указываются переменная и коллекция для перебора. При выполнении цикла Foreach среда Windows PowerShell автоматически создает переменную ($<элемент>). Перед каждой итерацией в цикле переменной присваивается значение в коллекции. Блок за инструкцией Foreach {<список_инструкций>} содержит набор команд, выполняемых на каждом элементе коллекции. Примеры Например, цикл Foreach в следующем примере отображает значения в массиве $letterArray. $letterArray = "a","b","c","d" foreach ($letter in $letterArray) { Write-Host $letter } В этом примере создается массив $letterArray, который затем инициализируется строковыми значениями "a", "b", "c" и "d". При первом выполнении инструкции Foreach переменная $letter устанавливается равной первому элементу в массиве $letterArray ("a"). Затем буква "a" отображается с помощью командлета Write-Host. При следующей итерации цикла переменной $letter присваивается значение "b" и т. д. После того как цикл Foreach отобразит букву "d", Windows PowerShell выходит из цикла. Инструкция Foreach должна представляться в одной строке целиком, чтобы она выполнялась как команда в командной строке Windows PowerShell. Инструкция Foreach не обязательно должна представляться в одной строке целиком, если команда помещается в файл скрипта PS1. Инструкции Foreach могут также использоваться совместно с командлетами, возвращающими коллекции элементов. В следующем примере инструкция Foreach выполняет перебор элементов списка, возвращаемого командлетом Get-ChildItem. foreach ($file in Get-ChildItem) { Write-Host $file } Пример может быть усовершенствован при помощи инструкции If для ограничения возвращаемых результатов. В следующем примере инструкция Foreach выполняет те же операции в цикле, что и в предыдущем примере, но здесь добавлена инструкция If, ограничивающая результаты файлами, размер которых превышает 100 килобайт (КБ). foreach ($file in Get-ChildItem) { if ($file.length -gt 100k) { Write-Host $file } } В этом примере цикл Foreach использует свойство переменной $file для выполнения операции сравнения ($file.length -gt 100k). Переменная $file содержит все свойства в объекте, возвращаемом командлетом Get-ChildItem. Поэтому может возвращаться не только имя файла. В следующем примере Windows PowerShell внутри списка инструкций возвращает длину и время последнего обращения: foreach ($file in Get-ChildItem) { if ($file.length -gt 100k) { Write-Host $file Write-Host $file.length Write-Host $file.lastaccesstime } } В этом примере в списке инструкций не обязательно выполнять только одну команду. Кроме того, можно использовать переменную вне цикла Foreach и увеличивать ее значение внутри цикла. Следующий пример подсчитывает файлы, размер которых превышает 100 КБ: $i = 0 foreach ($file in Get-ChildItem) { if ($file.length -gt 100k) { Write-Host $file "file size:" ($file.length / 1024).ToString("F0") KB $i = $i + 1 } } if ($i -ne 0) { Write-Host Write-Host $i " file(s) over 100 KB in the current directory."} else { Write-Host "No files greater than 100 KB in the current directory." } В предыдущем примере переменной $i присваивается значение 0 вне цикла, а увеличение значения происходит внутри цикла для каждого найденного файла размером больше 100 КБ. При выходе из цикла инструкция If вычисляет значение переменной $i для отображения количества всех файлов размером более 100 КБ. Либо отображается сообщение о том, что ни одного файла размером более 100 КБ не найдено. Предыдущий пример также демонстрирует, как форматировать результаты для длины: ($file.length / 1024).ToString("F0") Значение делится на 1024, чтобы показать результаты в килобайтах, а не в байтах. Полученное значение далее форматируется при помощи спецификатора формата с фиксированной запятой для удаления из результата дробной части. Значение 0 спецификатора формата указывает, что дробная часть отображаться не должна. Инструкция Foreach внутри конвейера команд Когда инструкция Foreach используется в конвейере команд, Windows PowerShell использует псевдоним foreach, вызывающий команду ForEach-Object. При использовании псевдонима foreach в конвейере команд не используется синтаксическая конструкция ($<элемент> in $<коллекция>), как это делается с инструкцией Foreach. Это является следствием того, что эти сведения предоставляет предыдущая команда в конвейере. Синтаксис псевдонима foreach, применяемого в конвейере команд, выглядит следующим образом: <команда> | foreach {<блок_команд>} Например, цикл Foreach в следующем конвейере команд отображает все процессы, рабочий набор (использование памяти) которых превышает 20 мегабайт (МБ). Оболочка Windows PowerShell передает выходные данные команды Get-Process по конвейеру псевдониму foreach. Внутри блока команд псевдонима foreach переменная $_.WS содержит значение свойства WS (рабочего набора), передаваемое ей командлетом Get-Process. (Часть $_ объявления является автоматической переменной WSH, а часть WS является свойством.) Инструкция If использует условное выражение для определения того, превышает ли рабочий набор 20 МБ (20 000 000 байт). Если превышает, то отображаются имя процесса, хранящееся в переменной $_.name, и размер рабочего набора в мегабайтах. При отсутствии рабочего набора процесса, размер которого превышает 20 МБ, ничего не отображается. Write-Host "Processes with working-sets greater than 20 MB" Get-Process | foreach { if ($_.WS -gt 20m) { Write-Host $_.name ": " ($_.WS/1m).ToString("F0") MB -Separator "" } } Кроме того, псевдоним foreach поддерживает понятия начального блока команд, среднего блока команд и конечного блока команд. Начальный и конечный блоки команд выполняются один раз, а средний блок команд выполняется каждый раз, когда цикл Foreach перемещается к очередному элементу коллекции или массива. Синтаксис псевдонима foreach, используемого в конвейере команд с начальным, средним и конечным блоками команд выглядит следующим образом: <команда> | foreach {<начальный_блок_команд>} {<средний_блок_команд>}{<конечный_блок_команд>} В следующем примере демонстрируется использование начального, среднего и конечного блоков команд. Get-ChildItem | foreach { $fileCount = $directoryCount = 0}{ if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}{ "$directoryCount directories and $fileCount files"} Начальный блок создает и инициализирует две переменных со значением 0: {$fileCount = $directoryCount = 0} Средний блок проверят, является ли возвращаемый командлетом Get-ChildItem элемент каталогом или файлом: {if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}} Если возвращаемый элемент является каталогом, значение переменной $directoryCount увеличивается на 1. Если элемент не является каталогом, на 1 увеличивается значение переменной $fileCount. Конечный блок выполняется после того, как средний блок завершит цикл и вернет результат операции: {"$directoryCount directories and $fileCount files"} При помощи структуры начального, среднего и конечного блоков и оператора конвейера можно переписать приведенный выше пример поиска файлов размером более 100 КБ следующим образом: Get-ChildItem | foreach{ $i = 0}{ if ($_.length -gt 100k) { Write-Host $_.name "file size:" ($_.length / 1024).ToString("F0") KB $i++ } }{ if ($i -ne 0) { Write-Host Write-Host "$i file(s) over 100 KB in the current directory." } else { Write-Host "No files greater than 100 KB in the current directory."} } СМ. ТАКЖЕ about_Automatic_Variables about_If Foreach-Object

winintro.ru

about_Foreach-Parallel

Эта документация перемещена в архив и не поддерживается.

Windows PowerShell 5.0

Обновлено: Май 2014 г.

Назначение: Windows PowerShell 3.0, Windows PowerShell 4.0, Windows PowerShell 5.0

РАЗДЕЛ

КРАТКОЕ ОПИСАНИЕ

Содержит описание языковой конструкции ForEach -Parallel в рабочем процессе Windows PowerShell®.

ПОДРОБНОЕ ОПИСАНИЕ

Параметр Parallel ключевого слова ForEach служит для выполнения команд в блоке сценария ForEach один раз для каждого элемента в указанной коллекции.

Элементы коллекции, например диск в коллекции дисков, обрабатываются параллельно. Команды в блоке сценария выполняются последовательно применительно к каждому элементу коллекции.

Конструкция ForEach -Parallel допустима только в рабочем процессе Windows PowerShell.

СИНТАКСИС

ForEach -Parallel ($<item> in $<collection>) { [<Activity1>] [<Activity2>] ... }

ПОДРОБНОЕ ОПИСАНИЕ

Как и в случае с оператором ForEach в Windows PowerShell, переменную, содержащую коллекцию ($<Коллекция>), необходимо определить до оператора ForEach -Parallel, но переменная, которая представляет текущий элемент ($<Элемент>), определяется в самом операторе ForEach –Parallel.

Конструкция ForEach -Parallel отличается от ключевых слов ForEach и Parallel. Ключевое слово ForEach обрабатывает элементы коллекции по порядку. Ключевое слово Parallel выполняет команды в блоке сценария в параллельном режиме. Блок сценария Parallel можно включить в блок сценария ForEach -Parallel.

Конечные компьютеры рабочего процесса, например, заданные с помощью общего параметра рабочих процессов PSComputerName, всегда обрабатываются параллельно. В этих целях указывать ключевое слово ForEach -Parallel не нужно.

ПРИМЕРЫ

Приведенный ниже рабочий процесс содержит оператор ForEach -Parallel, который обрабатывает диски, возвращаемые действием Get-Disk. Команды в блоке сценария ForEach -Parallel запускаются последовательно, но выполняются на дисках параллельно. Диски могут обрабатываться параллельно и в любом порядке.

workflow Test-Workflow { $Disks = Get-Disk # The disks are processed in parallel. ForEach -Parallel ($Disk in $Disks) { # The commands run sequentially on each disk. $DiskPath = $Disk.Path $Disk | Initialize-Disk Set-Disk -Path $DiskPath } } workflow Test-Workflow { #Run commands in parallel. Parallel { Get-Process Get-Service } $Disks = Get-Disk # The disks are processed in parallel. ForEach -Parallel ($Disk in $Disks) { # The commands run in parallel on each disk. Parallel { Initialize-Disk InlineScript {.\Get-DiskInventory} } } }

СМ. ТАКЖЕ

Создание рабочего процесса сценария (http://go.microsoft.com/fwlink/?LinkId=262872)

about_ForEach

about_Language_Keywords

about_Parallel

about_Workflows

technet.microsoft.com

Интересные примеры на PowerShell

10.1.2010 — Xaegr

Недавно натолкнулся вот на этот пост . В нём приведено несколько интересных примеров того “как в Perl одна-две строчки кода могут сделать больше, чем десять строк в каком-нибудь другом языке программирования” 😉 Мне показалось что будет интересно сравнить как эти примеры выглядели бы на PowerShell 😉 И главное – это может быть полезно тем кто уже знает Perl но сейчас изучает PS.

Как известно PowerShell очень молодой язык, и разумеется он унаследовал множество элементов других языков, и следовательно местами схож с многими из них. Я часто слышу о коде PowerShell фразы типа “О, да они же украли PHP!”, “Это же C# с более простым синтаксисом”. Но по-моему больше всего PowerShell похож на Perl. Это и не удивительно – Perl был одним из любимых языков авторов PS, и это здорово — многим хорошим особенностям в PS мы обязанны именно Perl’у.

“Hats off to superstar Larry Wall and Perl, very few people and technologies that have had the level of (positive 🙂) impact these 2 have had on the industry. The world is a better place because that guy was born! ”

Это была отмазка 😉 Теперь перейдем к коду 🙂

Сразу скажу – мне кажется это просто удачная подборка попалась, многие примеры удалось записать на PS сильно короче, и главное – понятнее (субъективно конечно 🙂). В очень многих областях Perl легко даст фору PowerShell’у в плане компактности кода, может быть даже и некоторые из этих примеров на Perl можно записать гораздо более красиво, так что буду рад если знающие Perl люди оставят свои конструктивные комментарии 🙂

Я цитирую только описания, код на Perl можно посмотреть в оригинальном посте .

1. Проверить, существует ли элемент (первый аргумент функции, передается по значению) в массиве (второй аргумент функции, передается по ссылке).

#Встроенный оператор -contains $array -contains $element

2. Удалить из массива @arr элементы, которые есть в массиве @skip.

#Вопросительный знак - алиас для where $arr | ? { $skip -notcontains $_ }

Вместо пункта 3 я написал красивый (субъективно разумеется 😉) фильтр:

filter Replace-Words { foreach ($arg in $args ) { $pair = $arg . split ("=" , 2 ) #Разрезаем аргумент на 2 части по знаку $_ = $_ -replace $pair [ 0 ] , $pair [ 1 ] #Заменяем вхождения в строке } $_ #Выдаём результирующую строку }

Использовать например так:

$text = Get-Content .\test1.txt $text | Replace-Words плохое=хорошее яблоки=груши | Set-Content .\test1.txt

4. Вывести список имен файлов и каталогов в заданной директории, отсортированный по дате последнего доступа. Обычно глобы сортируют список по имени файлов и каталогов. Для сортировки по дате последнего изменения, заменить цифру 8 на 9.

1. Написание скрипта

Скрипт PowerShell (не важно какой версии) - это текстовый файл с расширением *.ps1 .

Вот пример простого Power Shell срипта (файл systemInfo.ps1 ):

# Retrieve WMI object for the operating system

Get-WmiObject Win32_OperatingSystem

Этот файл можно создавать и редактировать, например, в FAR Manager.

Обратите внимание , что FAR Manager хоть и может работать в консоли Power Shell, но выполняет из-под себя скрипты в окружении обычной Windows-консоли cmd . То есть, FAR Manager можно использовать только для создания и редактирования PowerShell скриптов, но не для запуска. Но прежде чем разочаровываться, прочитайте пункт 3.

2. Запуск срипта

Скрипт нужно выполнять из консоли Power Shell, а не из обычной консоли Windows. В консоли Power Shell необходимо перейти в каталог, где лежит скрипт (командами cd ), и затем запустить сам скрипт, обязательно прописав перед ним символы ".\" . Например, имеем путь к файлу скрипта d:\work\systemInfo.ps1 . Тогда команды запуска будут выглядеть так:

d:

cd \

cd work

.\systemInfo.ps1

или так (просто указывается полный путь к скрипту):

d:\work\systemInfo.ps1

Скорее всего, при запуске скрипта появится следующая ошибка:

Не удается загрузить файл D:\work\systemInfo.ps1, так как выполнение скриптов запрещено для данной системы. Введите "get-help about_signing" для получения дополнительных сведений.

строка:1 знак: 18

CategoryInfo: NotSpecified: (:) , PSSecurityException

FullyQualifiedErrorId: RuntimeException

Ошибка появляется из-за того, что по-умолчанию в Power Shell включена максимальная политика безопасности, которая позволяет выполнять команды PowerShell в командной строке, но не позволяет в той же командной строке выполнить скрипт с командами PowerShell.

Чтобы резрешить выполнение PowerShell скриптов, нужно создать *.bat файл, например enableScript.bat со следующим содержимым:

powershell -Command Set-ExecutionPolicy RemoteSigned

Этот *.bat файл можно выполнить в любой консоли: хоть в PowerShell, хоть в обычной cmd . После выполнения этого файла, PowerShell-скрипты станут запускаться в консоли PowerShell.

3. Запуск PowerShell-скрипта из обычной Windows-консоли cmd

Скрипт PowerShell можно выполнить и из обычной консоли Windows. Для этого можно воспользоваться командой:

Powershell -File ./systemInfo.ps1

Таким образом можно выполнять скрипты прямо из FAR Manager, и они будут работать.

Но тут есть небольшая тонкость. Параметр -File срабатывает только на локальных путях, даже если путь указан относительный "./" . То есть, если *.ps1 - файл лежит на локальном диске C: или D: , то такой вызов будет работать. Но если попробовать выполнить скрипт, расположенный на доменном ресурсе, то скрипт не будет найден. Возможно, это исправят в следующих версиях PowerShell.

Управлять расширенными событиями SQL Server можно с помощью поставщика SQL Server PowerShell. Вложенная папка XEvent находится на диске SQLSERVER. Получить доступ к папке можно одним из следующих способов.

В дереве папки XEvent можно просматривать существующие сеансы расширенных событий и связанные с ними события, цели и предикаты. Например, если в папке PS SQLSERVER:\XEvent\ServerName \InstanceName > ввести cd sessions , нажать клавишу ВВОД, ввести dir и затем нажать клавишу ВВОД, то можно просмотреть список сеанс

crabo.ru