company_banner

Что такое Windows PowerShell и с чем его едят? Часть 2: введение в язык программирования

    Исторически утилиты командной строки в Unix-системах развиты лучше чем в Windows, однако с появлением нового решения ситуация изменилась.



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

    Оглавление:


    Комментарии
    Переменные и их типы
    Системные переменные
    Области видимости
    Переменные окружения (среды)
    Арифметические операторы и операторы сравнения
    Операторы присваивания
    Логические операторы
    Условный переход
    Циклы
    Массивы
    Хэш-таблицы
    Функции
    Обработка ошибок

    Писать код можно в любом текстовом редакторе или с использованием интегрированной среды разработки — проще всего взять Windows PowerShell ISE из комплекта поставки серверных операционных систем Microsoft. Нужно это только для достаточно сложных скриптов: короткие наборы команд проще выполнять в интерактивном режиме.

    Комментарии


    Использование комментариев считается частью хорошего стиля программирования наряду с правильными отступами и пробелами:

    # Для строчных комментариев используется символ решетки — содержимое строки интерпретатор не обрабатывает.
    
    <# 
    
           Так обозначаются начало и конец блочного комментария. 
           Заключенный между ними текст интерпретатор игнорирует.
    
    #>

    Переменные и их типы


    Переменные в PowerShell — это именованные объекты. Их названия могут включать символ подчеркивания, а также буквы и числа. Перед именем всегда используется символ $, а чтобы объявить переменную, достаточно указать интерпретатору допустимое имя:

    image

    Для инициализации переменной (присвоения ей значения) применяется оператор присваивания (символ =):

    $test = 100

    Объявить переменную можно с указанием ее типа в квадратных скобках (оператор приведения типов) перед именем или значением:

    [int]$test = 100
    
    $test = [int]100

    Важно понимать, что переменные в PowerShell — это полноценные объекты (классы) со свойствами и методами, типы которых основаны на имеющихся в .NET Core. Перечислим основные:
    Тип (класс .NET)
    Описание
    Пример кода
    [string]
    System.String
    строка Unicode 
    $test = «тест»
    $test = 'тест'
    [char]
    System.Char
    символ Unicode (16 бит)
    [char]$test = 'c'
    [bool]
    System.Boolean
    булевский тип (логическое значение True или False)
    [bool]$test = $true
    [int]
    System.Int32
    тридцатидвухразрядное целое число (32 бита)
    [int]$test = 123456789
    [long]
    System.Int64
    шестидесятичетырехразрядное целое число (64 бита)
    [long]$test = 12345678910
    [single]
    System.Single
    число с плавающей точкой длиною в 32 бита
    [single]$test = 12345.6789
    [double]
    System.Double
    число с плавающей точкой длиною в 64 бита (8 байт)
    [double]$test = 123456789.101112
    [decimal]
    System.Decimal
    число с плавающей точкой длиною в 128 бит (обязательно указывать d на конце)
    [decimal]$test = 12345.6789d
    [DateTime]
    System.DateTime
    дата и время 
    $test = Get-Date
    [array]
    System.Object[]
    массив, индекс элементов которого начинается с 0
    $test_array = 1, 2, «тест», 3, 4
    [hashtable]
    System.Collections.Hashtable
    хэш-таблицы — ассоциативные массивы с именованными ключами, построенные по принципу: @{ключ = «значение»}
    $test_hashtable = @{one=«один»; two=«два»; three=«три»}

    PowerShell поддерживает неявное преобразование типов, кроме того тип переменной может меняться на ходу (например, при помощи оператора присваивания), если он не указан принудительно — в этом случае интерпретатор выдаст ошибку. Определить тип переменной из предыдущего примера можно при помощи вызова метода GetType():

    $test.GetType().FullName

    image

    Существует некоторое количество командлетов для управления переменными. Их список в удобной форме выводится с помощью команды:

    Get-Command -Noun Variable | ft -Property Name, Definition -AutoSize -Wrap

    image

    Для просмотра объявленных переменных и их значений можно использовать специальный командлет:

    Get-Variable | more

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

    Системные переменные


    Помимо объявленных пользователем существуют встроенные (системные) переменные, которые не удаляются после завершения текущего сеанса. Делятся они на два типа, при этом данные о состоянии PowerShell хранятся в автоматических переменных, которым нельзя самостоятельно присвоить произвольные значения. К их числу относится, например, $PWD:

    $PWD.Path

    image

    Для хранения пользовательских настроек нужны переменные предпочтений, значения которых можно изменить. К примеру, с помощью $ErrorActionPreference задается реакция интерпретатора команд на возникновение некритических ошибок.

    Вдобавок к операторам и командлетам для обращения к объявленным переменным существует псевдонакопитель Variable:. Работать с ним можно по аналогии с другими накопителями, а переменные в этом случае напоминают объекты файловой системы:

    Get-ChildItem Variable: | more

    или

    ls Variable: | more

    image

    Области видимости


    Для переменных в PowerShell существует понятие области видимости (Scope). Действие глобальной области (Global) распространяется на весь текущий сеанс — в нее входят, например, системные переменные. Локальные (Local) переменные доступны только в области, где они были определены: скажем внутри функции. Есть еще понятие области действия сценария (Script), но для команд скрипта она по сути является локальной. По умолчанию при объявлении переменных им задается локальная область действия, а чтобы это изменить, нужна специальная конструкция вида: $Global: переменная = значение.

    Например, так:

    $Global:test = 100

    Переменные окружения (среды)


    Из PowerShell доступен еще один псевдонакопитель Env:, с помощью которого можно обратиться к переменным среды. При запуске оболочки они копируются из родительского процесса (т.е. из инициировавшей текущий сеанс программы) и обычно их первоначальные значения совпадают со значениями в панели управления. Для просмотра переменных окружения используется командлет Get-ChildItem или его псевдонимы (алиасы): ls и dir.

    dir Env:

    image

    Эти переменные представляют собой последовательности байтов (или символов, если угодно), интерпретация которых зависит только от использующей их программы. Командлеты *-Variable с переменными среды не работают. Чтобы обратиться к ним, придется использовать префикс диска:

    $env:TEST = "Hello, World!"

    image

    Арифметические операторы и операторы сравнения


    В PowerShell есть следующие арифметические операторы: + (сложение), — (вычитание), * (умножение), / (деление) и % (модуль или остаток от деления). Результат арифметического выражения вычисляется слева направо в соответствии с общепринятым порядком операций, а для группировки частей выражения применяются круглые скобки. Пробелы между операторами игнорируются, их используют только для облегчения восприятия. Оператор + также объединяет, а оператор * повторяет строки. При попытке прибавить число к строке оно будет преобразовано в строку. Кроме того, в языке PowerShell есть множество операторов сравнения, которые проверяют соответствие между двумя значениями и возвращают логические True или False:
    Оператор
    Описание
    Пример кода
    -eq
    Equal / Равно (аналог = или == в других языках)
    $test = 100
    $test -eq 123 
    -ne
    Not equal / Не равно (аналог <> или !=)
    $test = 100
    $test -ne 123   
    -gt
    Greater than / Больше (аналог >)
    $test = 100
    $test -gt 123
    -ge
    Greater than or equal / Больше или равно (аналог >=)
    $test = 100
    $test -ge 123
    -lt
    Less than / Меньше (аналог <)
    $test = 100
    $test -lt 123  
    -le
    Less than or equal / Меньше или равно (аналог <=)
    $test = 100
    $test -le 123

    Существуют и другие подобные операторы, позволяющие, например, сравнивать строки с учетом символа подстановки или использовать регулярные выражения для поиска соответствия образцу. Их мы подробно рассмотрим в следующих статьях. Символы <, > и = для сравнения не используются, поскольку задействованы для других целей.

    Операторы присваивания


    Помимо самого распространенного оператора = существуют и другие операторы присваивания: +=, -=, *=, /= и %=. Они изменяют значение перед присвоением. Аналогично ведут себя унарные операторы ++ и --, которые увеличивают или уменьшают значение переменной — они тоже относятся к операторам присваивания.

    Логические операторы


    Для описания сложных условий одного только сравнения недостаточно. Записать любые логические выражения можно с помощью операторов: -and, -or, -xor, -not и!.. Работают они как и в других языках программирования, при этом можно использовать круглые скобки, чтобы задать порядок вычисления:

    ("Тест" -eq "Тест") -and (100 -eq 100)
    
    -not (123 -gt 321) 
    
    !(123 -gt 321)

    Условный переход


    Операторы ветвления в PowerShell стандартные: IF(IF…ELSE, IF…ELSEIF…ELSE) и SWITCH. Рассмотрим их использование на примерах:

    [int]$test = 100
    if ($test -eq 100) {
          Write-Host "test = 100"
    }
    
    
    
    [int]$test = 50
    if ($test -eq 100) {
           Write-Host "test = 100"
    }
    else {
          Write-Host "test <> 100"
    }
    
    
    
    [int]$test = 10
    if ($test -eq 100) {
          Write-Host "test = 100"
    }
    elseif ($test -gt 100) {
          Write-Host "test > 100"
    }
    else {
           Write-Host "test < 100"
    }
    
    
    
    [int]$test = 5
    switch ($test) {
         0 {Write-Host "test = 0"}
         1 {Write-Host "test = 1"}
         2 {Write-Host "test = 2"}
         3 {Write-Host "test = 3"}
         4 {Write-Host "test = 4"}
         5 {Write-Host "test = 5"}
         default {Write-Host "test > 5 или значение не определено"}
    }
    

    Циклы


    В языке PowerShell есть несколько разновидностей циклов: WHILE, DO WHILE, DO UNTIL, FOR и FOREACH.

    Цикл с предусловием работает, если/пока оно выполняется:

    [int]$test = 0
    while ($test -lt 10) {
          Write-Host $test
          $test = $test + 1
    }
    

    Циклы с постусловием отработают хотя бы один раз, потому что проверка условия производится после выполнения итерации. При этом DO WHILE работает, пока условие истинно, а DO UNTIL — пока оно ложно:

    [int]$test = 0
    do {
          Write-Host $test
          $test = $test + 1 
    }
    while ($test -lt 10)
    
    
    
    [int]$test = 0
    do {
          Write-Host $test
          $test = $test + 1 
    }
    until ($test -gt 9)
    


    Количество итераций цикла FOR известно заранее:

    for ([int]$test = 0; $test -lt 10; $test++) {
           Write-Host $test
    }
    


    В цикле FOREACH осуществляет перебор элементов массива или коллекции (хэш-таблицы):

    $test_collection = "item1", "item2", "item3"
    foreach ($item in $test_collection)
    {
            Write-Host $item
    }
    

    Массивы


    В переменных PowerShell хранятся не только единичные объекты (число, строка и т.д.), но и множественные. Самая простая разновидность таких переменных — массивы. Массив может состоять из нескольких элементов, из одного элемента или быть пустым, т.е. не содержать элементов. Для его объявления используется оператор @(), который понадобится нам в следующей статье — он очень важен для добавления в массив других массивов (создания многомерных массивов), передачи массивов в функции в качестве аргумента и тому подобных задач:

    $test_array = @() #создаем пустой массив

    При инициализации массива его значения перечисляются через запятую (специальный оператор ,):

    $test_array = @(1, 2, 3, 4) # создаем массив из четырех элементов 

    В большинстве случаев оператор @() можно опустить:

    $test_array = 1, 2, 3, 4

    В этом случае массив из одного элемента инициализируется следующим образом

    $test_array = , 1

    Для обращения к элементам массива используется начинающийся с нуля целочисленный индекс и оператор индекса (квадратные скобки):

    $test_array[0] = 1

    Можно указать несколько индексов через запятую, в т.ч. повторяющихся:

    $test_array = "один", "два", "три", "четыре"
    $test_array[0,1,2,3]
    $test_array[1,1,3,3,0]

    image

    Оператор .. (две точки — оператор диапазона) возвращает массив целых чисел на определенном верхней и нижней границей отрезке. Например, выражение 1..4 выводит массив из четырех элементов @(1, 2, 3, 4), а выражение 8..5 — массив @(8, 7, 6, 5).

    image

    С помощью оператора диапазона можно инициализировать массив ($test_array = 1..4) или получить срез (slice), т.е. последовательность элементов одного массива с индексами из другого. При этом отрицательное число -1 обозначает последний элемент массива, -2 — предпоследний и т.д.

    $test_array = "один", "два", "три", "четыре"
    $test_array[0..2]
    $test_array[2..0]
    $test_array[-1..0]
    $test_array[-2..1]

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

    $test_array[0..100]

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

    image

    В PowerShell массивы могут содержать элементы разных типов или быть строго типизированными:

    $test_array = 1, 2, "тест", 3, 4
    for ([int]$i = 0; $i -lt $test_array.count; $i++)
    {
              Write-Host $test_array[$i]
    }
    

    Где свойство $test_array.count — количество элементов массива.

    Пример создания строго типизированного массива:

    [int[]]$test_array = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

    Хэш-таблицы


    Еще один базовый тип переменных в языке PowerShell — хэш-таблицы, которые также называют ассоциативными массивами. Hashtable похожи на JSON object и строятся по принципу ключ-значение. В отличие от обычных массивов, доступ к их элементам осуществляется по именованным ключам, которые являются свойствами объекта (также можно использовать оператор индекса — квадратные скобки).

    Пустая хэш-таблица объявляется с помощью служебного символа @ и операторных скобок:

    $test_hashtable = @{}

    При объявлении можно сразу создать ключи и присвоить им значения:

    $test_hashtable = @{one="один"; two="два"; three="три"; "some key"="some value"}

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

    $test_hashtable."some key"
    $test_hashtable["some key"]
    $test_hashtable.Add("four", "четыре")
    $test_hashtable.five = "пять"
    $test_hashtable['five'] = "заменяем значение"
    $test_hashtable.Remove("one")

    image

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

    Функции


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

    function имя-функции (аргумент1, ..., аргументN) 
    { 
            тело-функции 
    } 
    

    Функция всегда возвращает результат — это массив результатов всех ее стейтментов, если их более одного. Если стейтмент один, возвращается единственное значение соответствующего типа. Конструкция return $value добавляет элемент со значением $value к массиву результатов и прерывает выполнение statement list, а пустая функция возвращает $null.

    Для примера создадим функцию возведения числа в квадрат:

    function sqr ($number)
    {
          return $number * $number
    }
    

    Отметим, что в теле функции можно использовать любые объявленные до ее вызова переменные, а вызов функций в PowerShell может показаться непривычным: аргументы (если они есть) не заключаются в круглые скобки и разделяются пробелами.

    sqr 2

    или так:

    sqr -number 2

    Из-за способа передачи аргументов саму функцию иногда приходится заключать в скобки:

    function test_func ($n) {}
    test_func -eq $null     # функция не вызывалась
    (test_func) -eq $null   # результат выражения — $true

    image

    При описании функции можно присвоить аргументам значения по умолчанию:

    function func ($arg = value) {
             #тело функции
    }
    

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

    Обработка ошибок


    В PowerShell существует механизм Try…Catch…Finally, позволяющий обрабатывать исключительные ситуации. В блок Try помещается код, в котором может возникнуть ошибка, а в блок Catch — ее обработчик. Если ошибки не было, он не выполняется. Блок Finally выполняется после блока Try вне зависимости от возникновения ошибки, а блоков Catch может быть несколько для исключений различных типов. Само исключение записывается в не требующую объявления переменную по умолчанию ($_) и может быть легко извлечено. В примере ниже мы реализуем защиту от ввода некорректного значения:

    try {
    
            [int]$test = Read-Host "Введите число"
            100 / $test
    
    } catch {
    
             Write-Warning "Некорректное число"
             Write-Host $_
    
    }
    

    image

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

    Часть 1: основные возможности Windows PowerShell
    Часть 3: передача параметров в скрипты и функции, создание командлетов
    Часть 4: Работа с объектами, собственные классы


    RUVDS.com
    RUVDS – хостинг VDS/VPS серверов

    Комментарии 21

      +5
      Побольше бы таких доходчивых и полезных статей на Хабре.
      Без понтов и зашкаливающего эго.
        –1
        del
          +2

          Стоит, наверное, отметить, что массив object[] можно скастовать к конкретному типу, например, int[], если каждый элемент можно преобразовать.


          А еще PowerShell настолько интегрирован с dotnet, что одних массивов может быть недостаточно. Можно дергать и другие коллекции:


          > $coll = [System.Collections.Generic.List[int]]::New()
          > $coll.Add(5)
          > $coll
          > 5

          Или даже так:


          > [System.Linq.Enumerable]::Range(0, 10).Select([System.Func[int, int]]{param($x) $x * $x}) | Join-string -Sep ", "
          > 0, 1, 4, 9, 16, 25, 36, 49, 64, 81
            +1
            Что-то не получается.
            [System.Linq.Enumerable]::Range(0, 10).Select([System.Func[int, int]]{param($x) $x * $x}) Сбой вызова метода из-за отсутствия в [System.Int32] метода с именем "Select".
            строка:1 знак:1
            + ([System.Linq.Enumerable]::Range(0, 10)).Select([System.Func[int, int ...
            + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            + CategoryInfo : InvalidOperation: (:) [], RuntimeException
            + FullyQualifiedErrorId : MethodNotFound
              0

              Хм, интересно. Ответ оказывается простым.
              Я тестировал это в PowerShell Core 7.0-rc3 (stable-версия вроде только что вышла)
              В обычном PowerShell это действительно разваливается.


              В full-framework тип RangeIterator, который возвращается этим методом, имеет буквально несколько определенных методов. Проверить легко: запустите интерпретатор csi.exe. и выполните код:


              System.Linq.Enumerable.Range(0, 1)
                .GetType()
                .GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
                .Select(x => x.Name)
                .Aggregate((old, @new) => $"{old}, {@new}")

              Я получаю такой вывод:


              "Equals, GetHashCode, GetType, ToString"

              Теперь то-же самое для dotnet-script интерпретатора. Вывод следующий:


              "Clone, MoveNext, Dispose, Select, ToArray, ToList, GetCount, Skip, Take, TryGetElementAt, TryGetFirst, TryGetLast, get_Current, GetEnumerator, Where, ToString, Equals, GetHashCode, GetType"

              Т.е в .net core у вас определен инстанс-метод


              IEnumerable<TResult> RangeIterator.Select<TSource, TResult>(Func<TSource, TResult> selector)

              который и вызывается. В full framework такого метода нет и вместо него должен вызываться extension-метод


              IEnumerable<TResult> Enumerable.Select<TSource, TResult>(this IEnumerable<TSource> @this, Func<TSource, TResult> selector)

              и я полагаю PowerShell такие методы не понимает. Но это можно исправить вот так:


              [System.Linq.Enumerable]::Select([System.Linq.Enumerable]::Range(0, 10), [Func[int, string]]{param($x) ($x * $x).ToString()}) -join ", "

              В легаси PowerShell позходу и Join-String нет, но вот это выражение у меня работало и в PSCore 7.0.0-rc3, и в PS 5.1.x.

                +2
                Не получается, потому что Linq построен на методах раширения (extention method), позволяющих вызывать в качестве методов экземпляров класса методы, специальным образом определеные в другом классе. А в Powershell этот механизм не реализован. В нем соответсвующие методы нужно вызывать явно, через тот класс, в котором они реально определены.
                В Powershell для реализации аналогичной функциональности используется другой механизм, свойственный как раз shell-языкам: конвейер и команды (commandlet), которые принимают коллекции по конвейеру на вход, обрабатывают их элементы (или даже коллекцию целиком, например — сортируют ее) определенным образом и передают результат по конвейеру на выход. Скрипты, если они написаны определенным образом, тоже умеют так работать, в качестве таких команд-фильтров.
                Кстати, у Powershell есть в этом отношениии еще одна особенность. На выходе из конвейера наружу результаты выглядят как массив, если их несколько, или как одиночный элемент, если элемент один. Такое поведение удобно для интерактивной работы, но вот написание скриптов, наоборот, затрудняет.
              0
              Спасибо за статью. Хотелось бы почитать подробнее про командлет Start-Process и его параметр -Wait, абсолютно не понятно почему это работает с одними файлами инсталляторов и не работает с другими. Уже дошел до чтения кода функции, часто ей пользуюсь и каждый раз это лотерея.

              p.s .WaitForExit() не предлагать:)
                +2

                Некоторые "инсталяторы" распаковывают настоящий инсталятор, запускают его и сразу после этого завершают работу. В с ними-то никакой -Wait и не работает.

                  0
                  Да, с этим я и столкнулся, если передавать переменную процесса сразу в .WaitForExit() он берет только первый процесс из цепочки и радостно рапортует о завершении цикла, если использовать честный -Wait то он ждет пока все процессы цепочки завершатся, а самое интересное что инсталлятор не завершает их все и такой -Wait висит вечно. В итоге я сейчас просто ловлю пока в процессах появится определенный и грохаю ожидание. Какой-то парень предлагал написать таймаут для этого -Wait, даже написал, но его заклевали на гитхабе и PR закрыт.
                –4
                Перед именем всегда используется символ $

                [bool]$test = $true

                Так хочется это прокомментировать, что аж зубы сводит.
                Но — нельзя.

                  –4
                  Язык PS уродлив.

                  Как прочитавший который десяток спецификаций разных языков (см.публикации) скажу. Только эго заставило МС заменить вполне приличный c/jscript в системной командной строке
                    +3
                    Посмотрел кратко ваши публикации и не увидел, чтобы вы рассматривали хоть один язык командной оболочки (shell). Из чего заключаю, что вы просто оцениваете Powershell не в том контексте применения, для которого он предназначен.
                    Так вот, для языка комнадной оболочки написание программ (скриптов) — это только одна область примения, и не факт, что самая важная. Другая очень важная область применения такого языка — выдача интерактивных команд, причем часто — не одиночных команд, а их связок: взять выдачу одной команды, передать на вход другой для преобразования и т.д. Причем, часто бывает желательным, чтобы вся связка умещалась на одной строке — чтобы было проще вернуть её из истории (стрелкой вверх, например) и выполнить заново.
                    Лично мне, например, как системному администратору MS Exchange по основному роду занятий, такие вещи приходится проделывать очень часто.
                    Поэтому сложные конструкции из нескольких команд — типа набора операторов присваивания, операторов цикла — для интерактивной работы подходят плохо. А в языках командной оболочки для этой цели есть очень удобное средство — конвейер (pipe).
                    Есть и другие особенности Powershell — как свойственные многим другим языкам командной оболочки, так и уникальные именно для него — которые облегчают именно интерактивное выпонение команд. Надеюсь, авторы этой серии о них расскажут.
                      +1
                      А вот у меня лично, основные притензии именно к «интерактивным командам».
                      1. Длинные команды которые «не хочется» использовать.
                      Что бы найти нужный процесс, остановить запустить сервис или найти файл я не лезу в PS и т.д. и лично я, ещё не разу не видел, что бы кто то лез в PS, что бы наспех получить информацию от системы. Если единственный способ получить нужные данные, это PS апплет, тогда лезу в PS.
                      2. Медленный. Первый старт иногда приходится секунд 20 ждать, да даже задержка 3-5 секунд напрягает. Тот же cmd стартует мгновенно всегда. Я понимаю что объектная модель и все такое… но для «интерактивной работы» запуск оболочки должен быть мгновенный. У меня небольшой опыт в скриптописании, но все, что я делал на PS, python и bash, на PS всегда было очень медленно.
                      3. Риторический вопрос: Почему так поздно взялись за него?
                        +1
                        1. Длинные команды которые «не хочется» использовать.

                        Есть автокомплит и алиасы


                        Медленный. Первый старт иногда приходится секунд 20 ждать, да даже задержка 3-5 секунд напрягает.

                        Как вы этого добиваетесь? У меня разница в старте между cmd и ps визуально неразличима (и то и другое запускается мгновенно). Вы, наверное, про запуск ISE? Она, да, стартует секунды две. Но вас же никто не заставляет использовать ISE, можете запускать в любом терминале на свой выбор.

                          +1

                          Старт pscore начиная от 6й версии действительно очень медленный — на gihub по-этому поводу много issues. Одна только загрузка в терминале бывает длится секунду, и уж точно не мгновенно — это очень раздражает.

                      +1
                      Это специфика shell языков. Они все такие не от хорошей жизни. Основное назначение этой группы языков — командный интерпретатор в консоли.
                      Сложно совместить удобство работы в консоли с удобством написания скриптов.
                      0
                      вызов функций в PowerShell может показаться непривычным: аргументы (если они есть) не заключаются в круглые скобки и разделяются пробелами

                      А я вызываю так и все работает:
                      MyFunction($myVar)
                        +1

                        Просто у вас аргументом функции становится не $myVar, а ($myVar)

                          0
                          Именно. Причем, если так — в скобках через запятую — захотеть передать два аргумента, то внезапно будет передан один — массив из двух элементов.
                          PS А вот к вызовам методов объектов это не относится — методы вызываются именно со списком аргументов в скобках через запятую.
                        –1
                        Почему не Powershell Core?
                          +2
                          Хорошая статья с очень полезными, продуманными примерами. Подсмотрел несколько новых приемов, хотя в pwsh достаточно давно.

                          Хочу добавить: избегайте использования алиасов в обучающих статьях, это путает. Например, ft и more:
                          Get-Alias ft
                          CommandType     Name                                               Version    Source
                          -----------     ----                                               -------    ------
                          Alias           ft -> Format-Table  
                          

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

                          Самое читаемое