Глава 2. Введение в PowerShell 7

Данная глава рассматривает следующие рецепты:

  • Изучение новых операторов

  • Изучение параллельной обработки при помощи ForEach-Object

  • Изучение улучшений в ForEach и ForEach-Object.

  • Улучшения в Test-Connection

  • Применение Select-String

  • Изучение просмотра ошибок и Get-Error

  • Изучение экспериментальных функциональных возможностей

Введение

В Главе 1, Установка и конфигурирование PowerShell 7 вы установили и настроили PowerShell 7, причём совместно с VS Code и новым шрифтом. В этой главе мы взглянем на PowerShell 7 и то чем он отличается от Windows PowerShell. Все рецепты в этой главе иллюстрируют некоторые из наиболее важных функциональных возможностей, которые поступают с PowerShell 7.

Теперь, когда PowerShell является кросс- платформенным, он обладает новой, расширенной аудиторией, которая обладает за плечами оболочками Linux, такими как Bash. В PowerShell 7 команда PowerShell добавила некоторые новые операторы, которые улучшили соответствие с прочими оболочками и сделали жизнь для ИТ профессионалов чуточку проще.

После перехода на открытый исходный код сам код PowerShell стал открытым для инспекции его сообществом. Многие талантливые разработчики получили возможность выполнять улучшения для производительности и функциональности. Одним из примеров является то, как PowerShell выполняет итерации при помощи ForEach и ForEach-Object. В Windows PowerShell имевшийся синтаксис элемента ForEach и команды ForEach-Object позволял вам обрабатывать коллекции объектов. В Windows PowerShell каждая итерация по некой коллекции была последовательной, что могло иметь результатом длинные времена исполнения сценария. PowerShell 7 ввёл в команду ForEach-Object некое улучшение, которое сделало для вас возможным параллельное выполнение итераций. Такой пересмотр привёл к снижению общих накладных расходов применения таких популярных функциональных возможностей, тем самым ускоряя производительность сценариев.

Другим улучшением является пересмотр Test-Connection, команды, которую вы применяете для проверки сетевого соединения с удалённой системой. В PowerShell 7 Test-Connection не только делает больше, но и быстрее чем в Windows PowerShell.

Отчёты об ошибках в Windows PowerShell были исключительными: ясные и обычно имеющими практическое применение сообщения об ошибках с подробностями того где именно произошла ошибка. В PowerShell 7 вы теперь получаете, по умолчанию, лаконичное представление о некой ошибке без всего дополнительного текста, который часто не имел ценности. Как и всегда, вы можете вернуться к меньшей краткости, если пожелаете. В рецепте Изучение представления ошибки и Get-Error вы обнаружите насколько лучше в PowerShell 7 стали отчёты об ошибках (по сравнению с Windows PowerShell).

В заключительном рецепте этой главы мы взглянем на некоторые экспериментальные функциональные возможности, которые можно разрешить в PowerShell 7.

Изучение новых операторов

Операторы являются символами или сочетаниями нажатий клавиш, которые PowerShell распознаёт и придаёт им некое значение. PowerShell применяет оператор + имея в виду добавление, причём либо арифметическое сложение, либо добавление/ конкатенацию строк. Большинство популярных операторов было определено в Windows PowerShell v1.

PowerShell 7 реализовал некоторые новые операторы, включая следующие:

  • Операторы цепочек конвейеров: || и &&

  • Оператор объединения с null: ??

  • Присваивающий оператор при условии null: ??=

  • Экспериментальные операторы доступа к участнику при условии null: ?. и ?[]

  • Оператор обработки в фоновом режиме: &

  • Трёхместный (тернарный) оператор: ? <if-true> : <if-false>

  • : &

В данном рецепте вы рассмотрите образцы таких операторов.

Подготовка

Этот рецепт пользуется SRV1, хостом Windows Server 2022. Вы установили и настроили PowerShell 7 и VS Code. Все последующие рецепты данной книги вы исполняете либо в консоли PowerShell 7, либо в VS Code.

Как это сделать...

  1. Воспользуемся PowerShell 7 для традиционной проверки результатов

    
    Write-Output 'Something that succeeds'
    if ($?) {Write-Output 'It worked'}
    		
  2. Проверим результаты при помощи оператора конвейера &&

    
    Write-Output 'Something that succeeds' && Write-Output 'It worked'
    		
  3. Воспользуемся цепочным оператором конвейера ||

    
    Write-Output 'Something that succeeds' || 
      Write-Output 'You do not see this message'
    		
  4. Определим простую функцию

    
    function Install-CascadiaPLFont{
      Write-Host 'Installing Cascadia PL font...'
    }
    		
  5. Воспользуемся оператором ||:

    
    $OldErrorAction        = $ErrorActionPreference
    $ErrorActionPreference = 'SilentlyContinue'
    Get-ChildItem -Path C:\FOO\CASCADIAPL.TTF || 
       Install-CascadiaPLFont
    $ErrorActionPreference = $OldErrorAction
    		
  6. Создадим функцию для обработки null:

    
    Function Test-NCO {
      if ($args -eq '42') {
        Return 'Test-NCO returned a result'
      }
    }
    		
  7. Проверим результаты null традиционно:

    
    $Result1 = Test-NCO    # no parameter
    if ($null -eq $Result1) {
        'Function returned no value'
    } else {
        $Result1
    }
    $Result2 = Test-NCO 42  # using a parameter
    if ($null -eq $Result2) { 
        'Function returned no value'
    } else {
        $Result2
    }
    		
  8. Проверим применение оператора объединения с null ??:

    
    $Result3 =  Test-NCO
    $Result3 ?? 'Function returned no value'
    $Result4 =  Test-NCO 42
    $Result4 ?? 'This is not output, but result is'
    		
  9. Продемонстрируем null оператор присваивания по условию null:

    
    $Result5 = Test-NCO
    $Result5 ?? 'Result is null'
    $Result5 ??= Test-NCO 42
    $Result5
    		
  10. Традиционное исполнение метода с объектом null:

    
    $BitService.Stop()
    		
  11. Применение оператора с условием null:

    
    ${BitService}?.Stop()
    		
  12. Проверка доступа к имени свойства null:

    
    $x = $null
    ${x}?.Propname
    $x = @{Propname=42}
    ${x}?.Propname
    		
  13. Проверка доступа к участнику массива объекта null:

    
    $y = $null
    ${y}?[0]
    $y = 1,2,3
    ${y}?[0]
    		
  14. Применение оператора фоновой обработки &:

    
    Get-CimClass -ClassName Win32_Bios &
    		
  15. Ожидание завершения выполнения задания:

    
    $JobId = (Get-Job | Select-Object -Last 1).Id
    Wait-Job -id $JobId
    		
  16. Просмотр вывода

    
    $Results = Receive-Job -Id $JobId
    $Results | Format-Table
    		
  17. Создание объекта без помощи тернарного оператора:

    
    $A = 42; $B = (42,4242) | Get-Random
    $RandomTest = ($true, $false) | Get-Random
    if ($A -eq $B) {
      $Property1 = $true
    } else {
      $Property1 = $false
    }
    if ($RandomTest) {
      $Property2 = "Hello"
    } else {
      $Property2 = "Goodbye"
    }
    [PSCustomObject]@{
      "Property1" = $Property1
      "Property2" = $Property2
    }
    		
  18. Создание объекта с применением тернарного оператора:

    
    [PSCustomObject]@{
        "Property1" = (($A -eq $B) ? $true : $false)
        "Property2" = (($RandomTest) ? "Hello" : "Goodbye")    
    }
    		

Как это работает...

На Шаге 1 вы осуществляете вывод, который успешно завершается. Затем вы проверяете значение $? чтобы убедиться что предыдущий шаг был выполнен успешно. Вот что мы видим:

 

Рисунок 2-1


Традиционная проверка результатов

На Шаге 2 вы пользуетесь оператором && чтобы проверить, что предыдущая команда завершилась без ошибок. Вот как это выглядит:

 

Рисунок 2-2


Проверка результатов при помощи оператора конвейера

Оператор цепочки, || сообщает PowerShell необходимость выполнения команды после данного оператора, если предыдущая команда отказала (по действию, это противоположно &&). На Шаге 3 мы видим этот оператор в действии с выводом, подобным такому:

 

Рисунок 2-3


Традиционная проверка результатов

На Шаге 4 вы определяете некую функцию. Определение функции не производит вывод. Данная функция пишет вывод для имитации установки шрифта PL Cascadia Code.

На Шаге 5 вы проверяете имеется ли необходимый шрифт TTF и, если нет, вы вызываете функцию Install-CascadiaPLFont для имитации установки этого шрифта. Объединяя в конвейер вывод Get-ChildItem с Out-Null, вы избегаете реального вывода от Get-ChildItem и, когда необходимый файл отсутствует, вы можете вызвать функцию Install-CascadiaPLFont . Вывод этого фрагмента кода выглядит следующим образом:

 

Рисунок 2-4


Применение оператора || и установка шрифта Cascadia Code

Для иллюстрации обработки результатов null из функции, на Шаге 6 вы создаёте функцию, которая либо ничего не возвращает (когда вы вызываете функцию без параметров), или некое строковое значение (если вы вызываете её с определённым параметром). Данная функция иллюстрирует как вы можете обрабатывать некую функцию, возвращающую null. Этот шаг не производит вывода.

На Шаге 7 вы иллюстрируете традиционную обработку возвращающей null функции. Вы вызываете эту функцию, причём сначала без параметра, что приводит возврату без результата, а затем со значением, что и приводит к возврату значения. Затем вы проверяете вернула ли функция значение в каждом из случаев, что выглядит так:

 

Рисунок 2-5


Традиционная проверка на результат null

Когда вы пользуетесь оператором соединения с null (??) между двумя операндами, этот оператор возвращает значение операнда слева если оно не null; в противном случае он вычисляет операнд справа и возвращает его результат. На Шаге 8 вы вызываете функцию Test-NCO и проверяете будет ли функция возвращать некое значение, что выглядит следующим образом:

 

Рисунок 2-6


Тестирование при помощи объединяющего с null оператора

Для присвоения переменной некого значения, когда эта переменная в настоящее время null, вы пользуетесь оператором присвоения по условию null, ??=, что вы наблюдаете на Шаге 9, вывод которого таков:

 

Рисунок 2-7


Применение оператора присваивания по условию null

Одна из распространённых проблем, часто возникающая в различных форумах поддержки PowerShell, это когда вы пытаетесь активировать некий метод у объекта, которым выступает null. Вы можете воспользоваться неким выражением или командой чтобы попытаться вернуть некое значение (например, всех пользователей AD из офиса Marin County), а это возвращает значение null. На Шаге 10 вы активируете метод Stop() в объекте $BitService. Поскольку вы пока не назначили значения $BitService, вы наблюдаете соответствующий результат (ошибку, вы не можете вызвать метод в выражении со значением null). Наш традиционный метод отображает ошибку подобно следующей:

 

Рисунок 2-8


Традиционное выполнение метода для объекта null

Применяя оператор с условием null вы можете выполнять метод Stop(), когда переменная $BitService не null, но пропускать вызов этого метода, если переменная null. По существу, то что вы делаете на Шаге 11, так это вызываете метод Stop() если соответствующая переменная не null и не делаете ничего в противном случае. Поскольку эта переменная ещё не обладает значением, данный шаг не делает ничего (и не производит никакого вывода).

Когда переменная null, будь то по причине некой ошибки в вашем сценарии, или потому что команда возвращает null вместо некого реального значения, доступ к имени свойства также может вызывать ошибки. Вывод на Шаге 12 выглядит следующим образом:

 

Рисунок 2-9


Проверка доступа к свойству с названием null

Вы также можете сталкиваться с проблемами нулевых объектов когда вы пытаетесь получить доступ к некому участнику массива или объекта, который может существовать, а может и нет. На Шаге 13 вы пробуете получить доступ к некому участнику массива в не существующем массиве, за которым следует имеющийся массив. Вывод данного шага выглядит так:

 

Рисунок 2-10


Проверка доступа к участнику массива объекту null

На Шаге 14 вы изучаете применение оператора фонового процесса, &. Основная мысль состоит в том, что вы добавляете этот символ в конец некой команды или сценария и PowerShell исполняет такой код в фоновом режиме. Вот вывод данного шага:

 

Рисунок 2-11


Применение оператора фоновой обработки

На Шаге 15 вы дожидаетесь завершения того задания, которое вы создали на Шаге 14, что выглядит следующим образом:

 

Рисунок 2-12


Ожидание завершения задания

После завершения этого задания, на Шаге 16 вы получаете и отображаете вывод самого задания, который отображается так:

 

Рисунок 2-13


Отображение вывода задания

На Шаге 17 вы создаёте некий объект при помощи традиционного подхода. Данный шаг создаёт случайные значения для двух свойств. Затем вы создаёте объект применяя полученные значения для этих двух свойств. Вот вывод этого шага:

 

Рисунок 2-14


Создание объекта без помощи тернарного оператора

На Шаге 18 вы пользуетесь новым трёхместным (тернарным) оператором PowerShell 7. Этот оператор проверяет условие и исполняет различный код в зависимости от того истинный или ложный полученный результат. Это очень похоже на то, что вы наблюдали на Шаге 17, но требует гораздо меньшего числа строк. Вот как выглядит вывод этого шага:

 

Рисунок 2-15


Создание объекта без помощи тернарного оператора

Есть кое- что ещё...

На Шаге 4 создаваемая вами функция имитирует установку необходимого шрифта, если такой шрифт отсутствует. Сам файл шрифта, CASCADIAPL.TTF это TrueType файл шрифта для шрифта Powerline Cascadia Code. Для получения дополнительных сведений по этому шрифту, обращайтесь к https://www.hanselman.com/blog/PatchingTheNewCascadiaCodeToIncludePowerlineGlyphsAndOtherNerdFontsForTheWindowsTerminal.aspx.

На Шаге 5 вы имитируете установку необходимого шрифта если он отсутствует. Когда вы проверяете имеется ли в настоящее время установленным соответствующий файл TTF, настройка по умолчанию для $ErrorActionPreference (Continue) означает, что вы наблюдаете сообщение об ошибке если такой файл отсутствует. По умолчанию, когда Get-ChildItem выполняет проверку того имеется ли такой файл, он вырабатывает сообщение об ошибке в случае отсутствия файла. Одним из подходов для избежания такого сообщения об ошибке выступает настройка $ErrorActionPreference в SilentlyContinue и, после того как вы убедились что файл шрифта теперь имеется, установка обратно устанавливаемого по умолчанию значения. Синтаксис слегка путанный, если вы не знакомы с ним; это может быть ещё одним случаем, когда отказ от таких операторов и применение вместо них подхода Windows PowerShell может упростить чтение и понимание сценария.

На Шаге 11 и на Шаге 12 вы выполняете попытку осуществления доступа к свойству из некого объекта. Основное предположение здесь состоит в том, что вы желаете активировать соответствующий метод или доступ к значению свойства только когда такой объект имеется и не заботиться ни о чём в противном случае. Таким образом, если $BitService обладает неким свойством, вы вызываете метод Stop(), в противном случае сам код позаботится о том, чтобы соответствующий сценарий не вырабатывал ошибок. Такой подход великолепен для работе в командной строке, однако в промышленных сценариях этот подход способен маскировать прочие лежащие в основе проблемы. Как и в случае со всеми функциональными возможностями PowerShell, вам придётся применять обработку null с тщательностью и вниманием.

На Шаге 14 предписываете PowerShell выполнять команду как фоновое задание путём добавления в конец соответствующей команды символа &. Применение такого оператора более непосредственное нежели способ активации соответствующей команды в качестве задания через вызов Invoke-Command и определения такой команды при помощи параметров -ScriptBlock или -Script.

На Шаге 15 и на Шаге 16 вы пользуетесь Get-Job, Wait-Job и Receive-Job для ожидания того, чтобы ваше последнее задание выполнилось и получило вывод. Одним из недостатков отказа от применения Start-Job для фонового задания является то, что вы не можете определять название задания. Это подразумевает применение показанной на Шаге 15 техники для получения самого задания и результатов задания для созданного на Шаге 14 задания. Применение такой техники, тем самым, более полезно для применения из командной строки, нежели в неком промышленном сценарии.

На Шаге 17 вы создаёте объект с применением более старого синтаксиса Windows PowerShell, в то время как на Шаге 18 вы пользуетесь трёхместным оператором. Как и в случае прочих операторов, применяйте его внимательно, а когда вы задействуете такие операторы в промышленном коде, убедитесь что вы задокументировали то, что вы выполняете.

В данном рецепте вы рассмотрели новые операторы, добавленные в PowerShell 7. Большинство из них предоставляют более краткий способ выполнения некоторых действий, или прочего, в особенности из командной строки.

Изучение параллельной обработки при помощи ForEach-Object

Часто бывают ситуации когда вы желаете запустить несколько команд параллельно. Например, у вас может быть список имён компьютеров и для каждого из этих компьютеров вы хотите на этом компьютере запустить некий сценарий. Возможно, вы пожелаете проверить состояние и применение ресурсов различными службами на каждом из компьютеров. В таком случае вы можете воспользоваться Get-Content для получения массива названий компьютеров, а затем применять либо ForEach, либо ForEach-Object для запуска необходимого сценария на таком компьютере. Когда имеется 10 компьютеров и такому сценарию требуется 10 минут, общее время исполнения будет более 100 минут.

Для Windows PowerShell единственными встроенными методами параллельного исполнения сценариев состояло в применении заданий в фоновом режиме или применение рабочих процессов. При заданиях в фоновом режиме вы можете создать некий набор заданий, причём каждое из них запускает некий сценарий на отдельном компьютере. В таком случае PowerShell запускает каждое задание в отдельном процессе, что предоставляет изоляцию между всеми заданиями, но является ресурсо ёмким. Для Windows PowerShell V4 команда Windows PowerShell добавила рабочие процессы, которые также позволяют вам запускать блоки сценариев параллельно. Однако, рабочие процессы не переносятся в PowerShell 7. Как и прочие функции, которые большее не доступны в PowerShell 7, ы можете продолжать применять Windows PowerShell для выполнения рабочих процессов и постепенно преобразовывать их по мере необходимости.

Альтернативой фоновым заданием выступает применение модуля ThreadJob, который вы можете выгрузить из галереи PowerShell. За дополнительными сведениями относительно этого модуля обратитесь к его странице репозитория https://github.com/PaulHigin/PSThreadJob.

Для PowerShell 7 команда PowerShell добавила некий вариант для команды ForEach-Object чтобы позволить вам параллельно запускать блоки сценария. Этот вариант упрощает исполнение блоков сценариев в сценариях, в особенности сценариев длительного исполнения, причём параллельно и избегая потребности в модулях сторонних производителей или необходимости ведения дел со сложными рабочими процессами.

Данный рецепт демонстрирует традиционное параллельное исполнение операций, с применением заданий в фоновом режиме и при помощи ForEach-Object -Parallel.

Подготовка

Вы можете выполнять этот рецепт в SRV1 после того как вы установили PowerShell 7 и, не обязательно, VS Code.

Как это сделать...

  1. Имитируем блок сценария длительного исполнения:

    
    $SB1 = {
      1..3 | ForEach-Object {
        "In iteration $_"
        Start-Sleep -Seconds 5
      } 
    }
    Invoke-Command -ScriptBlock $SB1
    		
  2. Измеряем время исполнения

    
    Measure-Command -Expression $SB1
    		
  3. Преобразовываем в код, который применяет задания

    
    $SB2 = {
    1..3 | ForEach-Object {
      Start-Job -ScriptBlock {param($X) "Iteration $X " ;
                              Start-Sleep -Seconds 5} -ArgumentList $_ 
    }
    Get-Job | Wait-Job | Receive-Job -Keep
    }
    		
  4. Активируем этот блок сценария

    
    Invoke-Command -ScriptBlock $SB2
    		
  5. Определяем блок сценария при помощи ForEach-Object -Parallel

    
    $SB3 = {
    1..3 | ForEach-Object -Parallel {
                   "In iteration $_"
                   Start-Sleep -Seconds 5
             } 
    }
    		
  6. Выполняем этот блок сценария

    
    Invoke-Command -ScriptBlock $SB3
    		
  7. Измеряем время выполнения этого блока сценария

    
    Measure-Command -Expression $SB3
    		
  8. Создание и исполнение двух коротких блоков сценариев

    
    $SB4 = {
        1..3 | ForEach-Object {
                       "In iteration $_"
                 } 
    }
    Invoke-Command -ScriptBlock $SB4    
    $SB5 = {
            1..3 | ForEach-Object -Parallel {
                           "In iteration $_"
                 } 
    }
    Invoke-Command -ScriptBlock $SB5
    		
  9. Измеряем время исполнения для обоих блоков сценариев

    
    Measure-Command -Expression $SB4
    Measure-Command -Expression $SB5
    		
  10. Code

    
    > 
    		

Как это работает...

На Шаге 1 вы создали и затем активировали блок сценария. Этот блок сценария имитирует то как вы можете исполнять некие блоки сценариев с длительным временем выполнения традиционно при помощи командлета ForEach-Object со следующим выводом:

 

Рисунок 2-16


Имитация сценария с длительным времени исполнения

На Шаге 2 вы определяете как долго PowerShell выполнял этот блок сценария с выводом подобным следующему:

 

Рисунок 2-17


Измерение времени исполнения выражения

На Шаге 3 вы переписываете свой блок кода $SB1 на применение заданий PowerShell в фоновом режиме. Этот блок сценария запускает задачу с длительным временем исполнения, которое применяет задания и затем дожидается отображения вывода от каждого из заданий. Эта концепция состоит в том, что вместо последовательного выполнения каждой итерации, все задания выполняются параллельно. Определение таких функций не создаёт вывода.

На Шаге 4 вы активируете этот блок сценария для просмотра результатов, что выглядит так:

 

Рисунок 2-18


Имитация сценария с длительным временем исполнения

На Шаге 5 вы удаляете все имеющиеся задания и затем повторно исполняете свой обновлённый блок сценария. Этот шаг позволяет вам определить время выполнения всего выражения. Вывод на этом шаге отображается следующим образом:

 

Рисунок 2-19


Удаление всех имеющихся заданий и измерение времени исполнения соответствующего блока сценария

На Шаге 6 вы создаёте другой блок сценария с применением конструкции ForEach-Object -Parallel PowerShell 7. После создания этого блока сценария PowerShell не создаёт никакого вывода.

На Шаге 7 вы исполняете этот блок сценария, что выглядит так:

 

Рисунок 2-20


Удаление всех имеющихся заданий и измерение времени исполнения соответствующего блока сценария

На Шаге 8 вы измеряете время исполнения этого блока сценария с применением функциональной возможности ForEach-Object -Parallel, что отображается следующим образом:

 

Рисунок 2-21


Измерение времени исполнения соответствующего блока сценария

На Шаге 9 вы определяете, а затем активируете два блока сценария и это выглядит так:

 

Рисунок 2-22


Создание и исполнение двух коротких блоков сценариев

На завершающем шаге этого рецепта, Шаге 10, вы измеряете значение времени исполнения этих двух блоков сценариев:

 

Рисунок 2-23


Измерение времени исполнения блоков сценариев, созданных на шаге 9

Есть кое- что ещё...

На Шаге 1 и на Шаге 2 вы активируете много раз задачу с длительным временем исполнения. Как вы уже видели на Рисунке 17, исполнение этих блоков сценария, по одному за раз, занимает примерно 1 секунд. На Шаге 5 вы видите, что переписывание задачи с длительным временем исполнения на задания PowerShell в фоновом режиме, снижает время исполнения до 6.83 секунд. Наконец, на Шаге 8 вы измеряете истекшее время выполнения при применении ForEach-Object -Parallel, которое теперь менее 5 секунд.

Как показывает этот рецепт, когда у вас имеются независимые блоки сценария, вы можете исполнять их параллельно для снижения общего времени выполнения, в данном случае с более чеи 15 секунд до всего лишь около 5 секунд. И этот выигрыш был бы ещё больше если бы вы выполняли цикл более трёх раз. Последовательное выполнение цикла 10 раз отняло бы более 50 секунд, по сравнению с чуть более 5 секундами для ForEach-Object -Parallel.

Однако, существует ограничение по умолчанию в пять блоков сценария, которые PowerShell может исполнять одновременно. Для того чтобы разрешать больше или меньше чем по умолчанию, вы можете применять параметр -ThrottleLimit. Один момент, который следует отметить: когда вы пытаетесь выполнять больше параллельных блоков сценариев, чем у вас имеется ядер процессора, PowerShell просто применяет очередь ядра процессора. Это всё отнимает время и завершается ростом общего времени выполнения. Хорошая новость состоит в том, что всё это обрабатывает PowerShell, поэтому если, допустим, 1000 параллельных блоков сценария в системе с 12 ядрами процессора, PowerShell отработает настолько быстро, насколько позволит ваш компьютер хоста.

Также не лишним будет отметить, что имеются некие накладные расходы, вовлечённые в ForEach-Object -Parallel. Под своим капотом этой команде приходится настраивать, а затем и управлять исполнением отдельных потоков. Когда блок сценария очень короткий, вы можете обнаружить, что такие вовлекаемые в получение результатов накладные расходы замедляют время исполнения. В данном случае значение времени выполнения уходит с 2.9мс до 83.7мс. Собственно критическая точка здесь состоит в том, что эта конструкция полезна для нетривиальных блоков сценариев (или сценариев), которые работают параллельно. Вы черпаете выгоду до тех пор, пока не задействуете имеющееся число ядер.

Также следует отметить тот момент, что когда вы пользуетесь синтаксисом ForEach-Object {script}, вы применяете позиционный параметр (-Process). С другой стороны, когда вы применяете параметр -Parallel, значением этого параметра выступает число блоков сценария, которое вы желаете чтобы PowerShell исполнял параллельно.

Реализация в ForEach и ForEach-Object

Пользователи Windows PowerShell хорошо осведомлены как о применении оператора ForEach, так и об использовании командлета ForEach-Object. В своих сценариях вы можете применять оба эти метода для обработки имеющихся коллекций, таких как все рассматриваемые пользователи в конкретной группе Active Directory или все аудио файлы в неком совместно в файловом ресурсе. В PowerShell 7 оба этих метода итераций намного быстрее.

Применение любого из механизмов ForEach это быстрый и простой способ обработки некой коллекции. Одним из недостатков, которые некоторые из профессионалов ИТ могли заметить, состоит в том, что накладные расходы каждого ForEach в Windows PowerShell растут вместе с размером своей коллекции. При небольших размерах коллекции вы скорее всего не замечаете разницы. По мере роста размера этой коллекции в дело вступают накладные расходы.

Подготовка

Вы можете выполнять этот рецепт в SRV1 после того как вы установили PowerShell 7 и создали файл профиля консоли. Исполняйте этот рецепт в консоли с повышенными правами.

Как это сделать...

  1. Создайте удалённое подключение к локальному хосту при помощи Windows PowerShell

    
    New-PSSession -UseWindowsPowerShell -Name 'WPS'
    		
  2. Получите удалённый сеанс

    
    $Session = Get-PSSession -Name 'WPS'
    		
  3. Проверьте номер версии PowerShell в полученном удалённом сеансе

    
    Invoke-Command -Session $Session -ScriptBlock {$PSVersionTable}
    		
  4. Определите блок сценария длительного времени исполнения с применением ForEach-Object

    
    $SB1 = {
      $Array  = (1..10000000)
      (Measure-Command {
        $Array | ForEach-Object {$_}}).TotalSeconds
    }
    		
  5. Выполните этот блок сценария локально

    
    [gc]::Collect()
    $TimeInP7 = Invoke-Command -ScriptBlock $SB1
    "Foreach-Object in PowerShell 7.1: [{0:n4}] seconds" -f $TimeInP7
    		
  6. Выполните этот блок сценария в PowerShell 5.1

    
    [gc]::Collect()
    $TimeInWP = Invoke-Command -ScriptBlock $SB1 -Session $Session
    "ForEach-Object in Windows PowerShell 5.1: [{0:n4}] seconds" -f $TimeInWP
    		
  7. Определите другой блок сценария длительного времени исполнения с применением ForEach

    
    $SB2 = {
        $Array  = (1..10000000)
        (Measure-Command {
          ForEach ($Member in $Array) {$Member}}).TotalSeconds
    }
    		
  8. Выполните его локально в PowerShell 7

    
    [gc]::Collect()
    $TimeInP72 = Invoke-Command -ScriptBlock $SB2
    "Foreach in PowerShell 7.1: [{0:n4}] seconds" -f $TimeInP72
    		
  9. Запустите его вWindows PowerShell 5.1

    
    [gc]::Collect()
    $TimeInWP2 = Invoke-Command -ScriptBlock $SB2 -Session $Session
    "Foreach in Windows PowerShell 5.1: [{0:n4}] seconds" -f $TimeInWP2
    		

Как это работает...

На Шаге 1 мы пользуемся New-PSSession для создания удалённого сеанса с применением конечной точки Windows PowerShell. Этот шаг предоставляет такой вывод:

 

Рисунок 2-24


Создание удалённого подключения к вашему локальному хосту

На Шаге 2 вы получаете соответствующий объект сеанса, предоставляющий тот сеанс, который вы создали на предыдущем шаге. Это не производит никакого вывода.

На Шаге 3 вы получаете номер версии PowerShell, который применяет удалённые сеанс для обработки команд, а именно Windows PowerShell 5.1. Получаемый на этом шаге выглядит так:

 

Рисунок 2-25


Проверка номера версии в удалённом сеансе

На Шаге 4 вы создаёте блок сценария, $SB1, который применяет командлет ForEach-Object для выполнения итераций по большой коллекции. Данный шаг не выводит ничего.

На Шаге 5 вы активируете блок сценария $SB1 в локальном сеансе. Этот шаг исполняет ваш блок сценария в PowerShell 7. Вывод этого шага выглядит следующим образом:

 

Рисунок 2-26


Исполнение блока сценария локально

На Шаге 6 вы исполняете $SB1 в Windows PowerShell 5.1, что предоставляет вывод подобный такому:

 

Рисунок 2-27


Исполнение блока сценария в PowerShell 5.1

Затем, Шаге 7, вы создаёте блок сценария, который применяет элемент синтаксиса ForEach, не выдавая вывода. После этого, на Шаге 8, вы исполняете второй блок сценария в PowerShell 7, что предоставляет вывод, подобный приводимому ниже:

 

Рисунок 2-28


Исполнение блока сценария локально в PowerShell 7

На своём заключительном Шаге 9 вы запускаете $SB2 в созданном ранее удалённом сеансе (иными словами, в Windows PowerShell 5.1), что снабжает вас таким выводом:

 

Рисунок 2-29


Исполнение блока сценария в PowerShell 5.1

Есть кое- что ещё...

На Шаге 1 вы неявным образом создаёте удалённый сеанс с локальным хостом при помощи перемещения процесса, что намного быстрее чем традиционный удалённый сеанс с применением WinRM.

На Шагах 5, 6, 8 и 9 вы принуждаете .NET к сборке мусора. Именно эти шаги вы можете применять для минимизации снижения производительности при выполнении блока сценария в удалённом сеансе (Windows PowerShell) и уменьшить любое воздействие сборок мусора во время исполнения тестов данного рецепта.

Из получаемых выводов вы видите, что выполнение ForEach-Object в PowerShell 7 намного быстрее нежели выполнение ForEach PowerShell 7. Обработка больших коллекций объектов вообще намного быстрее в PowerShell 7.

Общее улучшение обработки цикла, которое вы наблюдаете в данном рецепте, сочетается с применением ForEach-Object -Parallel, которое вы наблюдали в Изучении параллельной обработки при помощи ForEach-Object, предоставляя исключительную причину переключаться на PowerShell 7 для большинства операций.

Значение производительности итераций о большим коллекциям это сложный вопрос. На этот предмет вы можете прочесть исключительную заметку https://powershell.one/tricks/performance/pipeline. Эта статья также адресована более подробному рассмотрению величины производительности с применением конвейера по сравнению с использованием ForEach для итераций по наборам.

Улучшения в Test-Connection

В Windows PowerShell вы можете применять командлет Test-Connection в качестве замены для команды консоли Win32 ping.exe. Одни из преимуществ применения этого командлета является то, что этот командлет возвращает объекты, которые могут более просто применяться при составлении сценариев. Для выделения неких сведений из вывода ping.exe вы можете пользоваться взломом строк и регулярными выражениями, но это достаточный объём дополнительной работы и результаты в сценариях, которые сложнее читать.

В Windows PowerShell 5.1 команда Test-Connection пользуется WMI. Эта команда возвращает некий объект с типом System.Management.ManagementObject#root\cimv2\Win32_PingStatus. Для PowerShell 7.1 эта команда больше не зависит от WMI и возвращает объекты с типом Microsoft.PowerShell.Commands.TestConnectionCommand+PingStatus. В результате такого изменения типа объекта, имена свойств, возвращаемых PowerShell 7.1 отличаются от свойств, возвращаемых в Windows PowerShell. Сценарии, применяющие некоторые свойства могут работать в PowerShell 7 некорректно без соответствующей регулировки, но это не должно быть общей проблемой.

Подготовка

Вы можете выполнять этот рецепт в SRV1 после того как вы установили PowerShell 7 и создали файл профиля консоли.

Как это сделать...

  1. Воспользуйтесь Test-Connection с параметром -Target

    
    Test-Connection -TargetName www.packt.com -Count 1
    		
  2. Примените Test-Connection с адресом IPv4

    
    Test-Connection -TargetName www.packt.com -Count 1 -IPv4
    		
  3. Разрешите адрес получателя при помощи Resolve-DnsName

    
    $IPs = (Resolve-DnsName -Name Dns.Google -Type A).IPAddress
    $IPs | 
      Test-Connection -Count 1 -ResolveDestination
    		
  4. Разрешите своего получателя и выполните traceroute

    
    Test-Connection -TargetName 8.8.8.8 -ResolveDestination -Traceroute |
      Where-Object Ping -eq 1
    		
  5. Примените бесконечный ping и остановку при помощи Ctrl-C

    
    Test-Connection -TargetName www.reskit.net -Repeat
    		
  6. Проверьте скорость Test-Connection в PowerShell 7

    
    Measure-Command -Expression {test-connection 8.8.8.8 -count 1}
    		
  7. Проверьте скорость Test-Connection в Windows PowerShell

    
    $Session = New-PSSession -UseWindowsPowerShell
    Invoke-Command -Session $Session -Scriptblock {
        Measure-Command -Expression {
          Test-Connection -ComputerName 8.8.8.8 -Count 1}
    }
    		

Как это работает...

На Шаге 1 вы проверяете соединение между SRV1 и вебсайтом нашего издателя. Вот вывод этой команды:

 

Рисунок 2-30


Применение Test-Connection с параметром -Target

Когда ваш компьютер работает с адресами IPv6, Test-Connection предпочитает применять по умолчанию IPv6, как это показано на Шаге 1. Когда вы желаете проверять именно соединение IPv4, вам требуется определять в явном виде переключатель -IPv4, как это показано на Шаге 2 :

 

Рисунок 2-31


Применение Test-Connection с адресом IPv4

На Шаге 3 вы пользуетесь командлетом Resolve-DnsName с целью определения IPv4 адреса (адресов) для Dns.Google. Эта площадка является бесплатной службой DNS Google, которую Google предлагает через два хорошо знакомых IPv4 адреса (8.8.8.8 и 8.8.4.4), что вы и можете наблюдать в выводе на этом шаге:

 

Рисунок 2-32


Применение Resolve-DnsName для разрешения адреса получателя

Приложение консоли Win32 tracert.exe позволяет вам отслеживать весь маршрут между хостом из вашей системы и неким внешним хостом. На Шаге 4 мы пользуемся Test-Connection для отслеживания всего маршрута между SRV1 и компьютером по адресу 8.8.8.8. Вот как выглядит этот вывод:

 

Рисунок 2-33


Разрешения самого получателя и отслеживание маршрута

При помощи приложения консоли Win32 ping.exe вы можете определить параметр -t для нескончаемого пинга к своему целевому хосту, который вы можете прекратить нажатием Ctrl-C. В PowerShell 7 при помощи Test-Connection вы можете применять параметр -Repeat для достижения того же вывода ( и остановки проверки по Ctrl-C). Вы наблюдаете этот вывод на Шаге 5:

 

Рисунок 2-34


Применение бесконечного ping и останов по Ctrl-C

На Шаге 6 и на Шаге 7 вы сравниваете скорость Test-Connection в Windows PowerShell и в PowerShell 7. Выполнение Test-Connection в PowerShell 7 выглядит так:

 

Рисунок 2-35


Проверка скорости Test-Connection в PowerShell 7

В Windows PowerShell 5.1 получаемый вывод аналогичен (хотя и медленнее) и отображается следующим образом:

 

Рисунок 2-36


Проверка скорости Test-Connection в Windows PowerShell

Есть кое- что ещё...

Из получаемого на Шаге 1 вывода мы можете наблюдать, что получаемые результаты форматируются иначе по сравнению с Windows PowerShell, причём с улучшениями предоставляемого вывода.

Шаг 2 показывает как PowerShell 7 способен применять переключатель -IPv4 для использования -IPv4 в явном виде. Аналогично, если вы желаете воспользоваться именно -IPv6, вы можете применить переключатель -IPv6. Никакой из этих переключателей не был доступен в Windows PowerShell.

На Шаге 3 вы определяете IP адреса для хоста Dns.Google (8.8.8.8 и 8.8.4.4), к которым затем успешно выполняется ping. Обратите внимание, что данный шаг выполняет разрешение IP адресов в имена хостов осуществляет ping для каждого из адресов. Google исполняет бесплатную службу DNS, доступную в интернете всем. Дополнительные сведения о ней вы можете найти на https://developers.google.com/speed/public-dns.

На Шаге 6 и на Шаге 7 вы сопоставляли скорость команды Test-Connection между Windows PowerShell 5.1 and PowerShell 7.1. Как вы можете наблюдать из полученных выводов, команда в PowerShell 7 значительно быстрее.

Применение Select-String

Входящая в состав Windows PowerShell команда Select-String была улучшена в PowerShell 7. Вы пользуетесь этой командой для поиска строк либо внутри объектов в конвейерах, либо в текстовых файлах. Данная команда концептуально аналогична команде Linux grep. В PowerShell 7 команда PowerShell добавила некоторые исключительные новые функциональные возможности для этой изумительной команды, которые мы и рассмотрим в данном рецепте.

Подготовка

Вы можете выполнять этот рецепт в SRV1 после того как вы установили PowerShell 7 и Visual Studio Code, а также создали файл профиля консоли.

Как это сделать...

  1. Получите некий текстовый файл для работы с ним

    
    $Source       = 'https://www.gutenberg.org/files/1661/1661-0.txt'
    $Destination  = 'C:\Foo\Sherlock.txt'
    Start-BitsTransfer -Source $Source -Destination $Destination
    		
  2. Получите содержимое этой книги

    
    $Contents = Get-Content -Path $Destination
    		
  3. Проверьте длину The Adventures of Sherlock Holmes

    
    "The book is {0} lines long" -f $Contents.Length
    		
  4. Поиск "Watson" в содержимом этой книги

    
    $Match1 = $Contents | Select-String -Pattern 'Watson'
    "Watson is found {0} times" -f $Match1.Count
    		
  5. Просмотр нескольких самых первых совпадений

    
    $Match1 | Select-Object -First 5
    		
  6. Поиск "Dr. Watson" при помощи регулярного выражения

    
    $Contents | Select-String -Pattern 'Dr\. Watson'
    		
  7. Поиск "Dr. Watson" при помощи простого совпадения

    
    $Contents | Select-String -Pattern 'Dr. Watson' -SimpleMatch
    		
  8. Просмотр содержимого вывода при поиске в файле

    
    Get-ChildItem -Path $Destination |
      Select-String -Pattern 'Dr\. Watson'
    		

Как это работает...

В данном рецепте мы рассмотрим как вы можете применять командлет Select-String, включаемый в PowerShell 7. Для исследования этого командлета вам сперва требуется выгрузить некий текстовый файл.

На Шаге 1 для выгрузки текста книги, The Adventures of Sherlock  Holmes, сэра Артура Конан Дойля, с вебсайта проекта Gutenberg вы применяете команду Start-BitsTransfer. Этот шаг не имеет вывода.

На Шаге 2 вы получаете весь текст из этой книги, который вы сохраняете в переменной $Contents . Этот шаг также не производит вывод. На Шаге 3 вы выдаёте отчёт об общей длине этой книги, который выглядит следующим образом:

 

Рисунок 2-37


Проверка общей длины книги

На Шаге 4 вы осуществляете поиск по содержимому этой книги для нахождения вхождений "Watson", преданного компаньона Шерлока Холмса. Это имеет результатом 81 вхождение и выглядит так:

 

Рисунок 2-38


Поиск вхождений "Watson" в этой книге

На Шаге 5 для просмотра первых пяти раз когда в содержимом книги обнаружен термин "Watson", вы пользуетесь командлетом Select-Object, что отображено ниже:

 

Рисунок 2-39


Просмотр первых пяти соответствий "Watson" из этой книги

При помощи Select-String вы можете задать некое регулярное выражение для соответствия искомому содержимому. На Шаге 6 вы определяете шаблон регулярного выражения для поиска строки "Dr. Watson". Получаемый вывод выглядит примерно так:

 

Рисунок 2-40


Поиск для "Dr. Watson" с помощью шаблона регулярного выражения

В качестве альтернативы применению регулярного выражения для выполнения поиска, Select-String также принимает простое соответствие, как это отображает вывод на Шаге 7:

 

Рисунок 2-41


Поиск для "Dr. Watson" с применением простого соответствия

На наших предыдущих шагах вы применяли Select-String для поиска содержимого некой переменной. Другая ценная функциональная возможность Select-String состоит в способности поиска в неком файле или даже во множестве файлов. Вы можете обнаружить это на Шаге 8, вывод которого приводится ниже:

 

Рисунок 2-42


Поиск для "Dr. Watson" в файле Sherlock.txt

Есть кое- что ещё...

На Шаге 1 и Шаге 2 вы выгружаете файл из проекта Gutenberg, бесплатной интернет библиотеки электронных книг. Эта площадка содержит большое число бесплатных книг в различных форматах, включая и основной текстовый. Для поиска дополнительных бесплатных книг посетите его домашнюю страницу https://www.gutenberg.org/, а для получения дополнительных сведений о самом проекте https://www.gutenberg.org/about/.

В качестве существенного улучшения Select-String в PowerShell 7 отметим выделение найденных строк, что вы можете наблюдать на Шаге 5, 6, 7 и 8. Это делает ещё более простым для употребления Select-String при просмотре вывода. Кроме того, возможность поиска по множеству файлов, как это показано на Шаге 8 , превращает Select-String в ещё более полезную.

Изучение представления ошибки и Get-Error

С самого своего начала Windows PowerShell выполнил великое задание по отображению результатов ошибок: большой ком красного текста на чёрном экране, который содержал полные сведения относительно того что пошло не так. Это было потрясающе, но многих новых пользователей это слегка отталкивало - слишком много сведений, часть которых в большинстве случаев не слишком полезны.

PowerShell 7 теперь предлагает более компактное представление об ошибках, уменьшающее объём текста и улучшающее формат вывода. Получаемый результат короче и более читаем. А в тех редких случаях, когда это может потребоваться, вы можете Get-Error для получения полных подробностей без необходимости синтаксического разбора через $Error[0].

Подготовка

Вы можете выполнять этот рецепт в SRV1 после того как вы установили PowerShell 7 и/ или Visual Studio Code, а также создали файл профиля консоли.

Как это сделать...

  1. Создайте простой сценарий

    
    $SCRIPT = @'
      # divide by zero
      42/0  
    '@
    $SCRIPTFILENAME = 'C:\Foo\ZeroDivError.ps1'
    $SCRIPT | Out-File -Path $SCRIPTFILENAME
    		
  2. Выполните этот сценарий и просмотрите установленное по умолчанию представление об ошибке

    
    & $SCRIPTFILENAME
    		
  3. Выполните ту же самую строку в своей консоли

    
    42/0
    		
  4. Просмотрите содержимое переменной $ErrorView

    
    $ErrorView
    		
  5. Просмотрите все потенциальные значения переменной $ErrorView

    
    $Type = $ErrorView.GetType().FullName
    [System.Enum]::GetNames($Type)
    		
  6. Установите $ErrorView в 'NormalView' и воссоздайте свою ошибку

    
    $ErrorView = 'NormalView'
    & $SCRIPTFILENAME
    		

    Установите $ErrorView в 'CategoryView' и воссоздайте свою ошибку

    
    $ErrorView = 'CategoryView'
    & $SCRIPTFILENAME
    		
  7. Установите $ErrorView в значение по умолчанию

    
    $ErrorView = 'ConciseView'
    		

Как это работает...

На Шаге 1 вы создаёте некий сценарий, который (умышленно) содержит ошибку деления на ноль. Этот шаг создаёт файл, но не производит вывода.

На Шаге 2 вы выполняете этот сценарий из VS Code и просматриваете получаемую в результате ошибку, выглядящую следующим образом:

 

Рисунок 2-43


Выполнение сценария и просмотр его ошибок

На Шаге 3 вы воссоздаёте ошибку деления на ноль в командной строке. на этом шаге вывод выглядит так:

 

Рисунок 2-44


Выполнение той же самой строки из консоли

PowerShell 7 пользуется переменной $ErrorView для содержания названия того представления об ошибках, которое надлежит применять PowerShell для отображения ошибок. На Шаге 4 вы просматриваете текущее значение этой переменной что отображается так:

 

Рисунок 2-45


Просмотр значения переменной $ErrorView

Переменная $ErrorView может принимать одно из трёх значений, как вы это можете наблюдать из вывода на Шаге 5

 

Рисунок 2-46


Просмотр потенциальных значений переменной $ErrorView

На Шаге 6 вы устанавливаете значение $ErrorView для отображения ошибок с применением вывода, вырабатываемого Windows PowerShell и воссоздаёте саму ошибку, которая теперь выглядит так:

 

Рисунок 2-47


Установка $ErrorView в NormalView и воссоздание ошибки

На Шаге 7 вы устанавливаете $ErrorView для отображения сообщения об ошибке при помощи CategoryView и далее воссоздаёте ту же ошибку. Получаемый на этом шаге вывод отображает представление о категории ошибки:

 

Рисунок 2-48


Установка $ErrorView в CategoryView и воссоздание ошибки

На Шаге 8 вы сбрасываете значение $ErrorView в установленное по умолчанию значение. Этот шаг не производит вывода.

Есть кое- что ещё...

Краткое представление об ошибке, которое вы наблюдаете на Шаге 2 содержит все сведения стандартного представления, которые вы обнаруживаете в выводе на Шаге 7, за исключением пропуска сведений о категории этой ошибки. А когда вы активируете эту ошибку непосредственно в командной строке, как это показано на Шаге 3, вы видите лишь сообщение об ошибке, что намного проще для наших глаз.

На Шаге 7 вы просматриваете сведения по категории своей ошибки, что не является особенно полезным.

На Шаге 8 вы сбрасываете значение $ErrorView. В зависимости от того что вы делаете, этот шаг может не быть необходимым. Вы просто можете покинуть PowerShell (или VS Code) и когда вы запустите свой PowerShell снова, он сбросит это значение в установленное по умолчанию (ConciseView). А если вы предпочтёт обычное представление категорий ошибок, вы всегда можете установить значение для $ErrorView в своём файле профиля.

Хотя это и не отражено в данном рецепте, вы можете применять командлет Get-Error для отображения полных сведений относительно конкретной ошибки. Для большинства профессионалов ИТ, те базовые сведения об ошибке, которые предоставляются PowerShell 7 более чем остаточные ( и выступают великолепным улучшением по сравнению с выводом сообщений об ошибках в Windows PowerShell).

Изучение экспериментальных функциональных возможностей

На протяжении разработки PowerShell Core и позднее, в PowerShell 7, команда PowerShell по ходу дела добавляла новые функциональные возможности. Некоторые из этих новых свойств способны, по крайней мере в теории, способны вызывать крушение имеющихся сценариев, и потому носят название "экспериментальных". По умолчанию, PowerShell не включает такие свойства. Как показывается в данном рецепте, вам надлежит разрешать их в явном виде. Такой подход к экспериментальным свойствам позволяет вам проверять эти новые функциональные возможности и снабжать команду PowerShell обратной связью. В случае когда вы обнаружите некое свойство, которое нарушает вам некий сценарий, запрещайте его. После того как вы включили (отключили) некую экспериментальную функциональную возможность, вам требуется перезапустить PowerShell 7.

В целом, экспериментальные свойства не имеют тенденции применяться в промышленных приложениях, так как такие экспериментальные функциональные возможности, по своей архитектуре, могут приводить к нарушениям. Кроме того, такие экспериментальные свойства не поддерживаются официально. При этом, до сих пор, эти функциональные возможности были стабильными и надёжными.

В данном рецепте вы рассмотрите те экспериментальные свойства, которые доступны в PowerShell 7.1 в том виде, как он выпущен. Если вы применяете более позднюю версию (например, предварительный выпуск PowerShell 7.2), вы можете обнаружить иные экспериментальные функциональные возможности, подробнее в https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_experimental_features.

Подготовка

Вы можете выполнять этот рецепт в SRV1 после того как вы установили PowerShell 7 и/ или Visual Studio Code, а также создали файл профиля консоли.

Как это сделать...

  1. Исследуем имеющиеся экспериментальные свойства

    
    Get-ExperimentalFeature -Name * |
      Format-Table Name, Enabled, Description -Wrap
    		
  2. Изучаем результат "команда не найдена" без каких бы то ни было доступных экспериментальных свойств

    
    Foo
    		
  3. Включаем одну из экспериментальных функциональных возможностей в качестве текущего пользователя

    
    Get-ExperimentalFeature -Name * | 
      Select-Object -First 1 |
        Enable-ExperimentalFeature -Scope CurrentUser -Verbose
    		
  4. Включаем одну функциональную возможность для всех пользователей

    
    Get-ExperimentalFeature -Name * | 
      Select-Object -Skip 1 -First 1 |
        Enable-ExperimentalFeature -Scope AllUsers -Verbose
    		
  5. Запускаем новую консоль PowerShell.

    Если вы пользуетесь VS Code, для запуска нового терминала нажмите Ctrl + Shift + `. Когда вы применяете консоль PowerShell 7, запустите новую копию консоли.

  6. Исследуйте имеющиеся новые экспериментальные свойства

    
    Get-ExperimentalFeature
    		
  7. Изучите вывод предлагаемый свойством "команда не найдена"

    
    Foo
    		

Как это работает...

На Шаге 1 для выявления всех доступных экспериментальных функциональных возможностей и их текущего состояния вы применяете командлет Get-ExperimentalFeature, который (по умолчанию) выглядит примерно так:

 

Рисунок 2-49


Изучаем экспериментальные свойства

Для проверки экспериментальных свойств на Шаге 2 вы исполняете не существующую команду, с подобным выводом:

 

Рисунок 2-50


Изучаем результат "команда не найдена"

На Шаге 3 вы включаете для своего текущего пользователя самое первое свойство, экспериментальную функциональную возможность PSCommandNotFoundSuggestion, что отображается так:

 

Рисунок 2-51


Включаем экспериментальные свойства для текущего пользователя

На Шаге 4 вы включаете вторую экспериментальную функциональную возможность, PSCultureInvariantReplaceOperator, что выглядит как показано ниже:

 

Рисунок 2-52


Включаем экспериментальные свойства для всех пользователей

На Шаге 5 вы запускаете новую версию PowerShell. Этот шаг не производит как такового вывода.

На Шаге 6 вы изучаете состояние экспериментальных свойств, причём никакие, за исключением двух, не доступны, что показано ниже:

 

Рисунок 2-53


Изучаем экспериментальные свойства

На Шаге 7 вы повторно исполняете неизвестную команду для просмотра предложений "команда не найдена", которое теперь отображается так:

 

Рисунок 2-54


Изучаем результат "команда не найдена"

Есть кое- что ещё...

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