## Начала работы с Microsoft PowerShell

(адаптация{*} для классов ТПТ)
Джеймс Э. Джарвис
24 ноября 2016 года

  http://www.docs.is.ed.ac.uk/skills/documents/3835/3835.pdf

------
{*} пример: "Обратная сторона Луны" -- российская адаптация американского сериала "Жизнь на Марсе"
------

## Содержание

  1 О PowerShell
  2 Начало работы
    2.1 Упражнение
  3 Команды
    3.1 Упражнение
  4 Псевдонимы
  5 Переменные в PowerShell
    5.1 Целочисленные переменные
    5.2 Переменные Double
    5.3 Переменные строк
    5.4 Специальные переменные
    5.5 Массивы
    5.6 Массивы объектов
    5.7 Хеши
    5.8 Удаление переменных
    5.9 Упражнение
  6 Среда PowerShell
  7 Перенаправление и трубы
  8 Чтение и запись в файлы
    8.1 Упражнение
  9 Скрипты
    9.1 Упражнение
  10 Логика и петли для управления потоком
    10.1 If
    10.2 For
    10.3.Foreach
    10.4 Упражнение
  11 Расширенные темы
    11.1 Больше о Date и Time.
    11.2 Упражнение
    11.3 Обработка данных -- использование файлов CSV
    11.4 Упражнение
    11.5 Дополнительно: обработка данных XML и загрузка .NET framework
  12 Дополнительная помощь
  13 Исходные тексты программ (Listings)


## 1. О PowerShell

Словосочетание PowerShell(R) является зарегистрированным товарным знаком корпорации Microsoft. PowerShell предоставляется корпорацией Microsoft и является хорошо продуманным, очень удобным и мощным языком сценариев (scripts). Можно увидеть влияние других языков сценариев и не только разработанных в Microsoft{*}.

------
{*} PowerShell -- это язык сценариев, созданный Microsoft, который сочетает в себе концепции Smalltalk, Perl и .NET.

http://www.flowgorithm.org/about/revisions.htm
------

Команды PowerShell (часто называемые командлетами) имеют форму:

  глагол-существительное

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

  Get-ChildItem

Сам PowerShell предоставляется как среда командной строки. В дополнение ко всем командлетам, из PowerShell можно напрямую вызвать не-PowerShell программу (например, notepad.exe).


## 2. Начало работы

В этом документе предполагается, что вы работаете на столах Windows Desktop поддерживаемых Университетом Эдинбурга. Упражнения могут работать и в других средах, но это не было проверено. При проработке этого документа вам может понадобиться выполнить поиск дополнительных модулей в Интернете и следовать инструкциям по их установке. Если вы не знаете, что делаете{*}, разумно устанавливать только дополнительные функции PowerShell с реальных (genuine) сайтов Microsoft.

------
{*} Unless you know what you are doing..
------

Читатели найдут упражнения более легкими, если у них есть предыдущий опыт написания сценариев или программ. Кроме того, PowerShell широко использует конвейеры, поэтому предварительное посещение курсов Unix-1 и Unix-2 даст преимущество.

PowerShell ISE (Integrated Scripting Environment) оказывается полезной для создания и редактирования сценариев.

  1. Нажмите кнопку «Пуск»

  2. Напечатайте PowerShell

  3. Теперь вы должны увидеть:

    + Windows PowerShell
    + Windows PowerShell (x86)
    + Windows PowerShell ISE
    + Windows PowerShell ISE (x86)

  images/ps.png

Рисунок 1: PowerShell -- среда командной строки.

  images/ps-ise.png

\"PowerShell ISE" (Integrated Scripting Environment) оказывается полезным при создании и редактировании сценариев.

Рисунок 2: PowerShell ISE -- встроенный редактор сценариев.

Выберите 64-битный вариант, указанный в списке как "Windows PowerShell". Закрепите икону на панели задач (pin to taskbar). Настройте фонт (есть русские буквы: Consolas, Lucida Console), удобные размеры фонта, окна, и цвета).


## 2.1. Упражнение

  1. Запустите PowerShell. Введите «exit» и нажмите клавишу «Enter». Что происходит?

  2. Запустите PowerShell ISE. Нажмите «Help». Нажмите «Update Windows PowerShell Help». Вы увидите в окне ниже команду `update-help`, а затем обычно вылетает сообщение об ошибке. Это нормально для поддерживаемых Университетом Эдинбурга столов Windows Desktop.

  3. Прочитайте красный текст ошибки. Можете ли вы определить, почему команда не удалась?


## 3. Команды

Формат команды:

  имя-команды [ключи настройки] [аргументы]

ключей настройки и аргументов может не быть или иметься один или несколько (Listing 1). Пользователи оболочек Unix быстро оценят, что разработчики PowerShell реализовали синтаксис команд аналогичным образом.

Команда `write-host` может использоваться без параметров, и в этом случае она создаст пустую строку вывода (см. Listing 2).

Мы можем найти опции для `write-host`, набрав` help write-host` (см. Listing 3). Для получения дополнительной информации добавьте опцию "-full":

  help -full write-host

Listing 1: формат команды PowerShell

  <command-name> -<Required Parameter Name> <Required Parameter Value>
                [-<Optional Parameter Name> <Optional Parameter Value>]
                [-<Optional Switch Parameters>]
                [-<Optional Parameter Name>] <Required Parameter Value>

Listing 2: Hello World

  PS M:\> write-host
  PS M:\> write-host "Hello World"
  Hello World

Таблица 1: Псевдонимы (aliases) некоторых команд PowerShell

  Команда         Псевдонимы

  clear-host      cls, clear
  format-list     fl
  get-childitem   gci, ls, dir
  get-content     gc, cat, type
  get-location    gl, pwd
  get-member      gm
  remove-item     ri, rm, rmdir, del, erase, rd
  write-output    write, echo


## 3.1. Упражнение

   1. Введите write-host "Hello World" и нажмите клавишу Enter

   2. Введите write-host -foregroundcolor yellow "Hello World"

   3. Заставьте PowerShell печатать в синим текстом на желтом фоне. Подсказка: используйте параметр -backgroundcolor.

   4. Введите help clear-host -online . Что происходит?


## 4. Псевдонимы

Многие команды имеют псевдонимы (см. Таблицу 1), и для тех, кто использовал DOS или Unix, они могут быть хорошо знакомы{1}. Псевдонимы -- это короткие формы команды. Поэтому те, кто использовал команду `pwd` напечатав `help pwd`, увидит, что основная команда на самом деле `get-location`. Однако, если вы использовали среду Unix или DOS, набор знакомых названий команд с чужеродными ключами и аргументами, упрощает использование powershell{2}.

------
{1} Ужасно, что работают они сильно иначе. В этом я вижу причину того, что многие люди опасаются одновременного владения английским и испанским языками, где около 400 слов звучат одинаково, но означают разное (false cognates).
  https://en.wikipedia.org/wiki
    /List_of_English–Spanish_interlingual_homographs
{2} ..а также позволяет эффективно забыть команды Unix или DOS.
------

Listing 3: Получение описания команды write-host

  PS M:\> help write-host

  NAME

    Write-Host

  SYNOPSIS

    Writes customized output to a host.

  SYNTAX

    Write-Host [[-Object] <Object>] [-BackgroundColor
    <ConsoleColor>] [-ForegroundColor <ConsoleColor>]
    [-NoNewline] [-Separator <Object>] [<CommonParameters>]

  DESCRIPTION

    The Write-Host cmdlet customizes output. You can specify the color of text by using the ForegroundColor parameter, and you can specify the background color by using the BackgroundColor parameter. The Separator parameter lets you specify a string to use to separate displayed objects. The particular result depends on the program that is hosting Windows PowerShell.

  RELATED LINKS

    Online Version:
    http://go.microsoft.com/fwlink/?LinkID=113426 Clear-Host
    Out-Host
    Write-Debug
    Write-Error
    Write-Output
    Write-Progress
    Write-Verbose
    Write-Warning

  REMARKS

    To see the examples, type: "get-help Write-Host -examples".

    For more information, type: "get-help Write-Host -detailed".

    For technical information, type: "get-help Write-Host -full".

    For online help, type: "get-help Write-Host -online"


## 5. Переменные в PowerShell

Переменные -- это метки, которые мы используем для хранения данных, которые могут меняться (отсюда и название «переменная»).

В PowerShell на переменные ссылаются (записать значение в область памяти с меткой "имя переменной") и разыменовывают (прочесть значение из области памяти с меткой "имя переменной") их предваряя имя переменной символом $ (dollar){*}

------
{*} Что понятно для случая бесплатного программного обеспечения с открытыми исходными кодами, где программист может испытывать недостаток в деньгах (ну хоть значков много:) -- языки программирования Perl, PHP..
------

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

  + integers (целые числа, положительные или отрицательные, например, 1, 5, -17, 0)

  + doubles (числа с десятичными знаками, положительные или отрицательные, e, g. 1.5, 5.0, -17.2, 0.45)

  + strings (строки -- последовательности символов, которые делают, например, слова или предложения)

  + arrays (массивы -- последовательности переменных, на которые ссылается целочисленный индекс, например строки могут рассматриваться как массивы)

  + hash tables (хэш-таблицы. иногда называемые словарями -- па'рами ключ -- значение)

  + objects (объект может содержать сложный набор типов переменных и ассоциаций) - некоторые примеры включают:

    o  процессы
    o  сервисы
    o  журналы событий
    o  компьютеры
    o  XML
    o  переменные могут понадобиться для всего, о чем вы можете подумать


## 5.1. Целочисленные переменные

Переменные могут хранить числа и для присваивания им значения, могут выполняться арифметические операции. Существует несколько типов переменных, которые могут содержать числа. Простейшим типом переменной является тип [int] для целых чисел (см. Listing 4).

Listing 4. Целочисленные переменные и арифметика

  PS M:\> [int] $a=5
  PS M:\> [int] $b=7
  PS M:\> $a
  5
  PS M:\> $b
  7
  PS M:\> $a+$b
  12

PowerShell пытается поступать правильно (trIEs to do the right thing). Переменная $a в Listing 5 является целым числом. Мы переопределяем (redeclare) $a, и она становится строкой. В случае сложения двух переменных, ответ будет зависеть от типа первой переменной.

Listing 5: Integers and strings

  PS M:\> [int] $b=7
  PS M:\> $a=4
  PS M:\> $a.getType().Name
  Int32
  PS M:\> $a+$b
  11
  PS M:\> $a="4"
  PS M:\> $a.getType().Name
  String
  PS M:\> $a+$b
  47
  PS M:\> $b+$a
  11


## 5.2. Переменные для работы с вещественными числами (doubles)

Переменные типа [double] похожи на целочисленные переменные, поскольку они содержат числа, однако число может содержать дробные части в виде десятичных знаков (см. Listing 6).


## 5.3. Строковые переменные

Чтобы присвоить значение «вторник» переменной «day», мы вводим `$day = "вторник", как показано в Listing 7.

Мы также можем попросить пользователя ввести информацию с помощью команды `read-host` (Listing 8).

Команда `read-host` отображает (echoes back) то, что было напечатано, однако, если мы присваиваем это значение переменной, например $name, то можем захватить пользовательский ввод для использования позже (см. Listing 9).

Listing 6: Арифметика вещественных чисел

  PS M:\> [double] $a=4.0
  PS M:\> [double] $b=3.5 PS M:\> $a-$b
  0.5

Listing 7: Строковые переменные

  PS M:\> $day="Tuesday"
  PS M:\>
  PS M:\> $day
  Tuesday
  PS M:\>

Listing 8: Чтение ввода

  PS M:\> read-host "What is your name:"
  What is your name:: James
  James

Строковые переменные могут иметь длину более одной строки, ограниченную двойными кавычками (см. Listing 10).

Дело становится более интересным, когда мы требуем явно (explicitly), что $a имеет тип string (Listing 11). Теперь, когда нужно сложить $a и $b, они суммируются как строки. Если мы изменим порядок и сложим $b и $a, результат будет целым числом. PowerShell выводит результат на основе типа первой переменной.

Как правило, PowerShell имеет хорошее представление о том, что вы имеете в виду, когда присваиваете значение новой переменной. Он будет также обеспечивать разумные преобразования там, где он может, но будьте бдительны при наборе выражений. Listing 12 иллюстрирует переменную $myvar, создаваемую как integer, становясь double, а затем string.

Обратите внимание, что BaseType для numeric является System.ValueType, тогда как для строк это System.Object. Обычно PowerShell воспринимает смешения System.ValueType разумно. Чтобы заставить переменную быть конкретным типом, вы указываете тип в квадратных скобках (см. Listing 13).


## 5.4. Специальные переменные.

Существует несколько специальных переменных:

  + $true

  + $false

  + $null

Listing 9: Сохранение ответа пользователя

  PS M:\> $name=read-host "What is your name:"
  What is your name:: Jane
  PS M:\> write-host $name
  Jane

Listing 10: Многострочные строковые переменные

  PS M:\> $workaddress="Main Library,
  >> George Square,
  >> Edinburgh"
  >>
  PS M:\> $workaddress
  Main Library,
  George Square, Edinburgh
  PS M:\> $workaddress
  Main Library,
  George Square,
  Edinburgh
  PS M:\>

Listing 11: Результаты могут быть неожиданными, когда типы переменных смешиваются

  PS M:\> [string] $a="4"
  PS M:\> [int] $b=7
  PS M:\> $a+$b
  47
  PS M:\> $b+$a
  11
  PS M:\>

Listing 12: Определение типа переменной или типа объекта

  PS M:\> $myvar=5
  PS M:\> $myvar.GetType()

  IsPublic IsSerial Name        BaseType
  -------- -------- ----        --------
  True     True     Int32       System.ValueType

  PS M:\> $myvar=$myvar+0.4
  PS M:\> $myvar
  5.4
  PS M:\> $myvar.GetType()

  IsPublic IsSerial Name        BaseType
  -------- -------- ----        --------
  True     True     Double      System.ValueType

  PS M:\> $myvar="7"+$myvar
  PS M:\> $myvar
  75.4
  PS M:\> $myvar.GetType()

  IsPublic IsSerial Name        BaseType
  -------- -------- ----        --------
  True     True     String      System.Object

  PS M:\>

Listing 13: Принудительное задание (declaring) типа переменной или типа объекта

  PS M:\> $a.GetType()

  IsPublic IsSerial Name        BaseType
  -------- -------- ----        --------
  True     True     Int32       System.ValueType

  PS M:\> [double] $q=$a
  PS M:\> $q.GetType()

  IsPublic IsSerial Name        BaseType
  -------- -------- ----        --------
  True     True     Double      System.ValueType

Listing 14: Строку можно читать как массив символов

  PS M:\> $i="cheese"
  PS M:\> $i[4]
  s
  PS M:\> $i[0]
  c
  PS M:\> $i.Length
  6

Если команда завершается успешно, то она вернет значение $true, а при неудаче вернет значение $false. Значение $null указывает, что переменная не задана. Установка значения переменной в $null эффективно удаляет эту переменную.


## 5.5. Массивы

Массивы представляют собой переменные с несколькими значениями с первым значением, индексированным как 0, второе как 1 и так далее. Мы уже использовали строковые переменные, и их можно разбить на массив символов, как в Listing 14.

Обратите внимание, как мы используем метод `.Length` для доступа к длине строки.

Мы также можем иметь массив строк как слова. Листинг 15 создает массив для хранения имен шотландских городов:

Обратите внимание, что длина -- это фактически количество элементов в массиве. Значения массива индексируются от 0 (ноль) -- в приведенном выше примере $city[0] будет иметь значение Edinburgh. Вот почему четвертый элемент, содержащий «Aberdeen», разыменован {1} как `$city[3]` .

------
{1} Разыменовывание переменной (Dereferencing a variable)
------

Листинг 15: массив, содержащий имена шотландских городов

  PS M:\> $city=("Edinburgh","Glasgow","Dundee","Aberdeen")
  PS M:\> $city[3]
  Aberdeen
  PS M:\> ($city).Length
  4

Listing 16: Список файлов папки это массив объектов файловой системы

  PS M:\> $myarray=get-childitem
  PS M:\> ($myarray).Count
  475
  PS M:\> $myarray[99]

  Directory: M:\

  Mode   LastWriteTime     Length  Name
  ----   -------------     ------  ----
  -a---  11/04/2014 17:09  95579   Advanced-PowerShell-To-Office365.docx

  PS M:\>


## 5.6. Массивы объектов

В Listing 16 мы используем команду `get-childitem` для получения содержимого файла и папки текущего каталога, но присваиваем результат` $ myarray`.

В вашем списке файлов может быть другое количество элементов, указанное переменной `($ myarray).Count`.


## 5.7. Хэш

Хеши или словарные объекты очень полезны. Они по существу являются массивами пар ключ-значение.

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

Listing 17 иллюстрирует использование хэша (см. Раздел 5.7 для хранения карты города для населения.)

В Listing 18 мы добавляем Falkirk (который не является городом, но имеет впечатляющее колесо и некоторые близлежащие келпи (Келпи представляют собой 30-метровые скульптуры лошадиных голов)).

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

  City       Population

  Glasgow    976970
  Edinburgh  488610
  Aberdeen   209460
  Dundee     157690

Таблица 2: Население шотландских городов. источник (Mid-2012 Populations Estimates for Settlements and Localities in Scotland from General Register Office of Scotland website)

Listing 17: Использование хэша для хранения названий шотландских городов и их населения

  PS M:\> $pops=@{"Glasgow"=976970;"Edinburgh"=488610;
  >> "Aberdeen"=209460;"Dundee"=157690}
  >>
  PS M:\> $pops

  Name       Value
  ----       -----

  Edinburgh  488610
  Glasgow    976970
  Dundee     157690
  Aberdeen   209460

  PS M:\>

Listing 18: Добавление записей в хэш.

  PS M:\> $pops.Add("Falkirk",100480)
  PS M:\> $pops

  Name       Value
  ----       -----

  Edinburgh  488610
  Glasgow    976970
  Falkirk    100480
  Dundee     157690
  Aberdeen   209460

  PS M:\>

Listing 19: Доступ к значению хэша (hash value) по его ключу.

  PS M:\> $pops."Aberdeen"
  209460
  PS M:\> $city="Aberdeen"
  PS M:\> $pops.$city
  209460
  PS M:\>

Listing 20: Доступ к значению хэша (hash value) вводом пользователем ключа:

  PS M:\> $pops=@{"Glasgow"=976970;"Edinburgh"=488610;
  >> "Aberdeen"=209460;"Dundee"=157690}
  >>
  PS M:\> $city=read-host "Enter a Scottish city:"
  Enter a Scottish city to be given its population: : Edinburgh
  PS M:\> $pops.$city
  488610
  PS M:\>

Не убедил? Ну, это действительно полезно для поисковых запросов, основанных на пользовательском вводе (см. Listing 20).


## 5.8. Удаление переменных

Самый быстрый способ удалить переменную -- установить ее в null, как в Listing 21.


## 5.9. Упражнение.

  1. Создайте переменную `$a` и присвойте ей значение 3, затем используйте команду` write-host` для отображения значения.

  2. Введите `$a.GetType()`, чтобы найти тип переменной `$a`

  3. Создайте переменную `$b` и присвойте ей значение 3.3, затем используйте команду` write-host` для отображения значения.

  Listing 21: Удаление переменной или объекта

    PS M:\> $myvar="Something"
    PS M:\> $myvar
    Something
    PS M:\> $myvar=$null
    PS M:\> $myvar
    PS M:\>

  Listing 22: Окружающая среда PowerShell (The PowerShell environment)

    PS C:\> get-item env:\

    Name                         Value
    ----                         -----

    SystemDrive                  C:
    ProgramFiles(x86)            C:\Program Files (x86)
    USERDNSDOMAIN                ED.AC.UK
    ProgramW6432                 C:\Program Files
    ..
    CommonProgramFiles(x86)      C:\Program Files (x86)\Common Files
    HOMEDRIVE                    M:
    windir                       C:\Windows
    NUMBER_OF_PROCESSORS         4
    OS                           Windows_NT
    ProgramFiles                 C:\Program Files
    ComSpec                      C:\Windows\system32\cmd.exe
    ..
    USERDOMAIN_ROAMINGPROFILE    ED
    PUBLIC                       C:\Users\Public

  4. Чтобы найти тип переменной `$b`, введите `$b.GetType()` .

  5. Создайте переменную `$c` и присвойте ей значение "3.3" (включая эти кавычки), затем используйте команду write-host для отображения значения.

   6. Введите `$c.GetType()`, чтобы найти тип переменной `$c`

   7. Присвойте переменной `$d` сумму первых двух переменных, набрав `$d = $a + $b`

   8. Какое значение возвращается при преобразовании значений 3.4 и 3.6 в целые числа? (Это может удивить тех, кто имеет опыт с Unix.)

  PS M:\> $a=[int] 3.4
  PS M:\> $b=[int] 3.6
  PS M:\> echo $a+$b
  3+4
  PS M:\> $d=$a+$b
  PS M:\> echo $d
  7


## 6. Окружающая среда PowerShell

Внутри shell, среда (environment) -- это термин для описания текущих настроек. Эти настройки отображаются в переменных среды. Так, например, имя переменной `username` содержит имя пользователя текущего вошедшего (logged on) пользователя, предположительно вас! В Listing 22 показана среда (некоторые значения опущены).

В Listing 23 показано, как получить доступ и присвоить одну переменную среды. Обратите внимание на использование круглых скобок вокруг команды, а затем добавления .value. Однако гораздо более простой синтаксис -- это `$env:varname`, который устраняет круглые скобки.

Листинг 23: Доступ к единому значению среды

  PS C:\> get-item env:\username

  Name       Value
  ----       -----
  USERNAME   jjarvis

  PS C:\> (get-item env:\username).value
  jjarvis
  PS C:\> $me=(get-item env:\username).value
  PS C:\> $me
  jjarvis
  PS C:> $env:username
  jjarvis


## 7. Перенаправление и трубы

Операторы перенаправления это символы `>` (больше чем) и `<` (меньше чем).

Символ `>` (больше чем) указывает, что выходные данные перенаправляются в файл (или во что-то, что ведет себя как файл). Символ `<` (меньше чем) указывает, что данные считываются из файла.

В Listing 24 показано, что cmdlet1 будет принимать входные данные  из файла c:fileA.txt, а вывод команды передается в cmdlet2; cmdlet2 отправит любой вывод в файл c:fileB.txt

Листинг 24: Доступ к единичному значению среды

  cmdlet1 < c:\fileA.txt | cmdlet2 > c:\fileB.txt

Трубы и перенаправление -- это сложные для освоения концепции. Если вы не использовали их прежде, уверьтесь, что это нормально, когда их трудно понять. Подводя итоги:

  + Трубы `|` находятся между командлетами, передавая выходные данные левого командлета на вход правого командлета.

  + Перенаправление контролирует поток между командлетом слева от символа и файлом справа.

  + Перенаправление `cmdlet < file` указывает, что информация для командлета считывается из файла

  + Перенаправление `cmdlet > file` указывает, что информация из командлета записывается в файл


## 8. Чтение и запись в файлы

  images/notepad.png

Рисунок 3: Пример текстового файла в редакторе Notepad.

Информация, которую мы используем на наших компьютерах, обычно хранится в файлах. PowerShell позволяет нам читать и записывать файлы. Мы начнем с обычного текстового файла, как показано на рисунке 3. Этот файл с именем example.txt имеет в нем следующий текст:

  Hello World

  This is a text document.

Предполагая, что вы создали написанное выше (используя notepad.exe), и сохранили его в файле m:\example.txt, вы сможете использовать команду `get-content` для проверки содержимого. В Listing 25 показано, как получить на экране содержимое файла и как назначить его переменной `$filecontent` для последующего использования.

На этот раз мы загрузим файл, а затем напишем его в новый файл с именем m:\hello.txt (см. Listing 26). Прежде чем мы напишем файл, мы убедимся, что hello.txt не существует, что является источником этих красных сообщений об ошибках.

Здесь мы знакомим вас с символом трубы -- вертикальной полоской `|` слева от команды `out-file`. Символ трубы указывает, что выход команды слева от нее передается как вход в команду справа. Таким образом, выше, вместо того, что значение $filecontent будет отправлено на экран (стандартный выход), вместо этого передается как вход в команду out-file.

Listing 25: Доступ к содержимому файла

  PS M:\> get-content M:\example.txt
  Hello World

  This is a text document.
  PS M:\> $filecontent=get-content m:\example.txt
  PS M:\> $filecontent
  Hello World

  This is a text document.
  PS M:\>

Listing 26: Запись в файл

  PS M:\> Get-Content .\example.txt
  Hello World

  This is a text document.
  PS M:\> $filecontent=Get-Content .\example.txt
  PS M:\> get-content .\hello.txt
  ‘ get-content: Cannot find path 'M:\hello.txt'
  ‘       because it does not exist.
  ‘ At line:1 char:1
  ‘ +  get-content hello.txt
  ‘ +  ~~~~~~~~~~~~~~~~~~~~~
  ‘ +  CategoryInfo:  ObjectNotFound:
  ‘                   (M:\hello.txt:String) [Get-Content],
  ‘                   ItemNotFoundException
  ‘ +  FullyQualifiedErrorId : PathNotFound ,
  ‘      Microsoft.PowerShell.Commands.GetContentCommand
  PS M:\>$filecontent
  Hello World

  This is a text document.
  PS M:\> $filecontent | out-file hello.txt
  PS M:\> get-content hello.txt
  Hello World

  This is a text document.
  PS M:\>

Listing 27: Использование get-member (gm) для обнаружения того, какие методы могут быть применены к переменной.

  PS M:\> $filecontent | gm

    TypeName: System.String

  Name        MemberType       Definition
  ----        ----------       ----------
  Clone       Method           System.Object Clo...
  CompareTo   Method           int CompareTo(Sys...
  Contains    Method           bool Contains(str...
  CopyTo      Method           void CopyTo(int s...
  ..

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

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

Наша переменная $filecontent имеет тип «объект», что означает, что не обязательно очевидно, для чего вы можете ее использовать. Здесь удобно использовать символ трубы и `get-member`. `Get-member` настолько полезен, что вы найдете себя приказывающим использовать эту команду очень часто, поэтому, если вы предпочитаете меньше набирать текст, вам может быть приятно узнать, что существует псевдоним `gm`. Вот `gm` в действии:

  missing Listing?

  just appetizing, don't take it serious

Результат был свернут здесь, но обычно `gm` покажет вам, что вы можете делать или использовать из объекта или переменной. Помните ранее `($city).Length`? Используя `$city | gm` станет понятным, что Length является свойством переменной `$city`, которое можно запросить.

## 8.1. Упражнение

  1. Создайте и сохраните текстовый файл, содержащий ваш адрес. Вызовите файл address.txt. Используйте `get-content` для отображения содержимого файла address.txt.

  2. Назначьте содержимое address.txt переменной `$address` и отобразите содержимое.

  3. Создайте многострочную строковую переменную `$workaddress` с вашим рабочим адресом.

  4. Создайте переменную `$myname` с вашим именем и фамилией в ней. Используйте символ трубы и `gm`, чтобы определить, какие методы доступны, чтобы сделать все в верхнем и нижнем регистре.

Listing 28: Ввод команд в скрипт, который сообщает введенное имя и текущий год

  # This is a comment -- commenting your scripts will make them
  # more understandable for yourself and others.
  # Comments begin with the hash symbol #

  ### Store today’s year in a variable called "year"

  $year=(get-date -UFormat "%Y")

  ### Ask the user for their name and store in variable "name"

  $name=read-host "What is you name?"

  ### Write out a reply using the values name and day

  write-host "Hello $name.  This year is $year"


## 9. Скрипты

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

В Listing 28 подробно описывается последовательность команд, которые можно ввести в PowerShell ISE. Сохраняя приведенный выше список в m:\report-thisyear.ps1, затем сценарий может быть запущен (или выполнен), нажав кнопку запуска в PowerShell ISE (см. Рис. 4).

В качестве альтернативы откройте окно PowerShell, Выполните команду cd в ту же папку, что и сохраненный файл, и введите:

  .\report-thisyear.ps1.


## 9.1. Упражнение

  1. Введите Listing 28 в файл с помощью notepad.exe.

  2. Сохранить как «report-thisyear.ps1» (вам нужно изменить расширение файла).

  3. Попробуйте запустить «report-thisyear.ps1» -- вам нужно будет указать полный путь к скрипту.

  4. Откройте «report-thisyear.ps1» в Notepad.exe снова. Скопируйте весь код в буфер обмена.

  5. Откройте PowerShell ISE

  6. Вставьте содержимое буфера обмена в новый документ в PowerShell ISE.

        images/script-in-psise.png

      Рисунок 4: Запуск сценария в ISE PowerShell.

  7. Сохранить как «report-thisyear2.ps1».

  8. Используйте кнопку запуска для запуска скрипта

Хотя сценарии PowerShell могут быть написаны в Notepad.exe, должно быть очевидно, что использование PowerShell ISE имеет ряд преимуществ.


## 10. Логика и циклы для управления потоком (flow control)

PowerShell, как и другие среды кодирования, позволяет задавать вопросы и циклировать определенное количество раз в скриптах. Возможность делать что-то, зависящее от чего-то другого, или повторять серию команд -- это ключ к полезности скриптов. Они позволяют нам экономить время, выполняя приземленные предсказуемые процессы (mundane predictable processes).

Listing 29: Использование операторов if else и elseif

  [string] $name=read-host "What is your name? "
  if ( $name.length -lt 5 ) {
    write-host "$name is a short name"
  } elseif ( $name.length -lt 9 ) {
    write-host "$name is a medium length name"
  } else {
    write-host "$name is long  -- are you tired typing it?"
  }

Listing 30: Использование цикла for

  PS M:\svn> for ($a = 50; $a -ge 0; $a=$a-10) {
  >> $a
  >> }
  >>
  50
  40
  30
  20
  10
  0
  PS M:\svn>


## 10.1. if

В Listing 29 показано управление потоком, основанное на операторах if, else и elseif. Компьютеры запрашивают ваше имя и затем выводят другое сообщение, основанное на значении (длине) имени. Если скрипт запущен, то Jim, Claire и Ebeneezer получат различные ответы.


## 10.2. for

Команда `for` позволяет выполнить итерации в нектором диапазоне с заданной последовательностью шагов. В Listing 30 мы имеем обратный отсчет с шагом -10 от 50 до 0. Обычно обычно делается подсчет с шагом +1, в случае которого `$a = $a + 1` (сокращенная запись `$a++`).


## 10.3. foreach

Если вы помните, у нас ранее была переменная $city, у которой было четыре значения. Четыре значения это не так много, но их может быть тысячи. В листинге 31 приведена численность населения городов и вычисляется и средняя. Скрипт выполняет следующий текст для каждой строки:

Листинг 31: Использование foreach для перебора массива объектов

  PS M:\> $pops=@{"Glasgow"=976970;"Edinburgh"=488610;
  >> "Aberdeen"=209460;"Dundee"=157690}
  >>
  PS M:\> [double] $total=0
  PS M:\> foreach ($city in $pops.Keys) {
  >>   $total=$total+$pops.$city
  >> }
  >> $average=$total / ($pops).Count
  >> write-host "Total population: $total, average: $average"
  >>
  Total population: 1832730, average: 458182.5

Listing 32: Использование трубы и `measure-object`, чтобы избежать необходимости в цикле

  $pops=@{"Glasgow"=976970;"Edinburgh"=488610;
  >> "Aberdeen"=209460;"Dundee"=157690}
  >>
  ($pops.Values | Measure-Object -average ).Average

  1. Хэш-переменная `$pops` инициализируется именем и численностью населения для четырех шотландских городов.

  2. Мы инициализируем переменную `$total` с типом double и нулевым значением.

  3. Команда `foreach` указывает, что, в свою очередь, для каждого значения в `$pops.$keys` мы должны присвоить это значение `$total` переменной `$city` и применить код между фигурными открывающейся `{` и закрывающейся `}` скобками.

  4. Одна строка внутри фигурных скобок добавляет численность населения текущего значения переменной `$city`, обращаясь к хэш-символу `$pops.$city` .

  5. Цикл `foreach` перезапускается со следующим значением в `$pops.Keys`, когда он встречает закрывающуюся скобку `}` до тех пор, пока остаются значения.

  6. Значение переменной `$average` рассчитывается с использованием `$total`, деленного на число городов в `$pops.Count`.

  7. Результаты распечатываются.

Конечно, вычисление среднего является довольно распространенным требованием. В PowerShell обычно можно делать что-то более чем одним способом. Мы могли бы упростить задачу, устраняя необходимость в цикле, вместо этого используя команды `pipe` и `measure-object`, как в Listing 32.

Listing 33: Сколько времени прошло с тех пор, как родился Нельсон Мандела?

  PS M:\> [datetime] $born="18 July 1918"
  PS M:\> ((get-date).Year-$born.Year)
  96
  PS M:\> ((get-date)-$born)
  Days              : 35202
  Hours             : 10
  Minutes           : 25
  Seconds           : 37
  Milliseconds      : 526
  Ticks             : 30414903375268673
  TotalDays         : 35202.4344621165
  TotalHours        : 844858.427090796
  TotalMinutes      : 50691505.6254478
  TotalSeconds      : 3041490337.52687
  TotalMilliseconds : 3041490337526.87

  PS M:\>


## 10.4. Упражнение

  1. Откройте PowerShell ISE

  2. Напишите сценарий с хешем людей, которых вы знаете, и их днем рождения.

  3. Добавьте вопрос, чтобы спросить имя человека.

  4. Верните день рождения для этого человека.


## 11. Расширенные темы

## 11.1. Еще о date и time

Те, кто писал сценарии на других языках, знают, что использовать date и time может быть интересно! PowerShell отлично справляется с датой и временем. Дата и время хранятся в переменных типа

  datetime

Listing 33 - это пример, показывающий дату рождения Нельсона Манделы и количество времени, прошедшего с тех пор. Обратите внимание, что когда два значения типа datetime вычитаются разность будет типа timespan , который измеряется в тиках (tick). Одна секунда длится десять миллионов тиков.

Listing 34: Назначение даты

  PS M:\> [datetime] $b="11:25 pm 7 July 1998"
  PS M:\> $b

  07 July 1998 23:25:00

В Listing 34 показано назначение временной точки переменной `[datetime]`. PowerShell делает разумную работу чтобы понять, что же имеется в виду, но рекомендуется проверять стиль ввода, поскольку «pm» он понимает, а вот «p.m.» уже нет!


## 11.2. Упражнение

Используя PowerShell сосчитайте, прожили ли вы:

  1. Миллион секунд?

  2. Миллион минут?

  3. Миллион часов?

  4. Рассчитайте свой возраст в единицах миллионов минут.


## 11.3. Обработка данных - использование файлов CSV

В Таблице 5.7 было собрано население шотландских городов. Возможность доступа к таблицам данных и управление ими является важной частью современной экономики знаний. У PowerShell есть некоторые очень полезные функции для доступа к данным и чтения данных из файлов.

Возможность чтения и обработки этих данных может быть очень полезна. Существуют способы обращения к файлам Excel с использованием COM-объекта Excel.Application, однако в этих примерах будут использоваться форматы файлов CSV и команда PowerShell `import-csv`.

Таблица 11.3 это представление содержимого файла «element.csv».

В Listing 35 показано, как мы можем получить доступ к этим данным в PowerShell.

Таблица 3: Избранные химические элементы и их свойства

  Element   Symbol  Protons  Neutrons

  Iron      Fe      26       30
  Oxygen    O       8        8
  Hydrogen  H       1        0
  Carbon    C       6        6

Listing 35: Импорт CSV-файла в табличный объект данных

  PS C:\Workspace> $elements=Import-Csv .\element.csv
  PS C:\Workspace> $elements
  Element      Symbol
  Protons      Neutrons
  -------      ------
  -------      --------
  Iron         Fe
  26           30
  Oxygen       O
  8            8
  Hydrogen     H
  1            0
  Carbon       C
  6            6

  PS C:\Workspace> $elements.Protons
  26
  8
  1
  6
  PS C:\Workspace> ($elements.Protons | Measure-Object -sum).sum
  41

Listing 36: 36 XML доступа к иерархии университета

  PS C:\Workspace> $webClient = new-object System.Net.WebClient
  PS C:\Workspace> $webClient.Headers.Add("user-agent", "PowerShell Script")
  PS C:\Workspace> $url="https://www.org.planning.ed.ac.uk/webware/units.xml"
  PS C:\Workspace> $webClient.DownloadFile($url,"c:\workspace\units.xml")
  PS C:\Workspace> [xml] $hierarchy=Get-Content C:\Workspace\units.xml


## 11.4. Упражнение

  1. Создайте CSV-файл элементов со значениями, показанными в таблице 11.3.

  2. Импортируйте данные в переменную $elements

  3. Рассчитайте среднее число протонов (подсказка: Measure-Object average)

  4. Напечатайте символы элементов у которых число протонов, равно числу нейтронов.


## 11.5. Дополнительно: обработка данных XML и загрузка .NET framework

Многие данные, включая метаданные, теперь хранятся в EXtensible Markup Language (XML). PowerShell может обрабатывать объекты, являющиеся XML, объявляя их как `XML`

------
{*} Зачастую в формате JSON
------

Пример в Listing 36 загружает текущую иерархию организаций Университета Эдинбурга. Для этого нам нужно загрузить объект System.NetcWebClient. Если вы уже использовали VBScript ранее, загрузка .NET framework будет вам знакома.

Теперь в $hierarchy у нас есть иерархия объектов XML. К сожалению, файл XML -- это просто плоский экспорт единиц с полем, в котором указывается, на каком уровне они находятся, и кто является их родителем. Мы можем видеть это, если мы выберем строки уровня 2 университетской иерархии, как в Listing 36. Обратите внимание, что для краткости показаны только первые и последние единицы уровня 2.

В идеале XML будет структурирован иерархически. Чтобы преобразовать XML, нам нужно загрузить другую инфраструктуру .NET. Нам также нужно преобразование, которое, к счастью, доступно как веб-загрузка. В Listing 38 подробно описано, как мы используем другую инфраструктуру .NET для преобразования в XML. Обратите внимание, что URL-адрес завернут (wrapped). Преобразованный объект XML в $tree имеет массив колледжей в верхнем узле university.

Листинг 37: Доступ к уровням иерархии университетского уровня 2 (колледжи)

  PS C:\Workspace> $hierarchy.ROWSET.ROW | where {$_.UNIT_LEVEL -eq 2}

  num                      : 2
  UNIT_CODE                : HSS
  UNIT_DESCRIPTION_LONG    : College of Humanities and Social Science UNIT_DESCRIPTION_SHORT   : HSS
  UNIT_LEVEL               : 2
  UNIT_PARENT              : UOE
  CATEGORY_AB_ACTIVITY     : A
  URL                      : http://www.hss.ed.ac.uk/
  UNIT_ADDRESS_LINE_1      : 57 George Square
  UNIT_ADDRESS_LINE_2      : Edinburgh
  UNIT_POSTCODE            : EH8 9JU
  CURRENT_STATUS           : A
  ACTIVE_FROM_DATE         : 2002-08-01T00:00:00
  HEAD_OF_UNIT             : Professor XXXXXXXXXXX
  HOU_EMAIL                : Head.CHSS@ed.ac.uk
  HOU_ADDRESS_LINE_1       : 55 George Square
  HOU_ADDRESS_LINE_2       : Edinburgh
  HOU_POSTCODE             : EH8 9JU
  CONTACT                  : XX XXXXXX XXXXXX
  CONTACT_EMAIL            : XXXXX.XXXXXX@ed.ac.uk
  CONTACT_ADDRESS_LINE_1   : 55 George Square
  CONTACT_ADDRESS_LINE_2   : Edinburgh
  CONTACT_POSTCODE         : EH8 9JU
  LAST_UPDATED             : 2014-02-27T15:31:00
  UPDATED_BY               : ORG
  SORT_DESCRIPTION         : 1
  ..
  ..
  num                      : 9
  UNIT_CODE                : ACS
  UNIT_DESCRIPTION_LONG    : Student and Academic Services
  UNIT_DESCRIPTION_SHORT   : SASG
  UNIT_LEVEL               : 2
  UNIT_PARENT              : UOE
  URL                      : http://www.ed.ac.uk/misc/acss.html
  UNIT_ADDRESS_LINE_1      : Old College
  UNIT_ADDRESS_LINE_2      : South Bridge
  UNIT_ADDRESS_LINE_3      : Edinburgh
  UNIT_POSTCODE            : EH8 9YL
  CURRENT_STATUS           : I
  ACTIVE_FROM_DATE         : 2002-08-01T00:00:00
  INACTIVE_FROM_DATE       : 2006-02-06T00:00:00
  HEAD_OF_UNIT             : XX XXXX XXXXXXX
  HOU_EMAIL                : University.Secretary@ed.ac.uk
  HOU_ADDRESS_LINE_1       : Old College
  HOU_ADDRESS_LINE_2       : South Bridge
  HOU_ADDRESS_LINE_3       : Edinburgh
  HOU_POSTCODE             : EH8 9YL
  LAST_UPDATED             : 2006-02-06T16:20:00
  UPDATED_BY               : XXXXX
  SORT_DESCRIPTION         : 4


## 12. Дальнейшая помощь

В PowerShell легко сделать быстрые эксперименты о том, как он будет себя вести. В сочетании с командлетом get-method (псевдоним gm) можно быстро оценить, какие методы доступны для объектов. Иногда объект будет непрозрачным, но веб-поиск обычно покажет некоторые существующие варианты использования. Едва ли нужно говорить, что лучшим источником для окончательных ответов является Microsoft, но для примеров особенно полезны Microsoft Scripting Guys. В первую очередь воспользуйтесь их примерами.

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

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

Listing 38: Преобразование XML

  PS C:\> $webClient = new-object System.Net.WebClient
  PS C:\> $webClient.Headers.Add("user-agent", "PowerShell Script")
  PS C:\> $xslurl="http://edin.ac/1DydneY"
  PS C:\> $xslfile="c:\workspace\uoe-create-hierarchical.xsl"
  PS C:\> $webClient.DownloadFile($xslurl,$xslfile)
  PS C:\> $xslt = New-Object System.Xml.Xsl.XslCompiledTransform
  PS C:\> $xslt.Load($xslfile)
  PS C:\> $xslt.Transform("C:\Workspace\units.xml","C:\Workspace\tree.xml")
  PS C:\> [xml]$tree=Get-Content C:\Workspace\tree.xml
  PS C:\> $tree

  xml                             university
  ---                             ----------
  version="1.0" encoding="utf-8"  university

  PS C:\Workspace> $tree.university

  unit                  : UOE
  UNIT_CODE             : UOE
  UNIT_PARENT           :
  UNIT_DESCRIPTION_LONG : University of Edinburgh
  UNIT_LEVEL            : 1
  LAST_UPDATED          : 2002-10-25T00:00:00
  UPDATED_BY            : ORG
  college               : {college, college, college, college... }

  PS C:\Workspace> $tree.university.college[0]

  unit                  : HSS
  UNIT_CODE             : HSS
  UNIT_PARENT           : UOE
  UNIT_DESCRIPTION_LONG : College of Humanities and Social Science
  UNIT_LEVEL            : 2
  LAST_UPDATED          : 2014-02-27T15:31:00
  UPDATED_BY            : ORG
  node                  : node

  PS C:\Workspace


## 13. Listings

 1 Формат команды
 2 Hello, World
 3 Получение справки для команды write-host
 4 Целочисленные переменные и арифметика
 5 Целые числа и строки
 6 Арифметика с числами с десятичными точками
 7 Строковые переменные
 8 Чтение ввода пользователя
 9 Сохранение ответа пользователя
10 Многострочные строковые переменные
11 Результаты могут быть неожиданными, если типы переменных смешиваются
12 Определение типа переменной или объекта
13 Форсирование (объявление) типа переменной или объекта
14 Строку можно рассматривать как массив символов
15 Массив, содержащий названия шотландских городов
16 Список файлов -- это массив объектов файловой системы
17 Использование хеша для хранения названий шотландских городов и численности их населения
18 Добавление в хеш-таблицу
19 Доступ к хеш-значению с использованием его ключа
20 Доступ к хеш-значению с использованием ввода от пользователя
21 Удаление переменной или объекта
22 Окружающая среда PowerShell
23 Доступ к единичному значению среды
24 Доступ к единичному значению среды
25 Доступ к содержимому файла
26 Запись в файл
27 Использование get-member (gm) для определения того, какие методы могут быть применены к переменной
28 Ввод команд в скрипт, который приветствует текущий год
29 Использование операторов if else и elseif
30 Использование цикла for
31 Использование foreach для перебора массива объектов
32 Использование трубы и `measure-object`, чтобы избежать необходимости в цикле
33 Сколько времени прошло с тех пор, как родился Нельсон Мандела?
34 Назначение даты
35 Импорт CSV-файла в табличный объект данных
36 XML доступа к иерархии университета
37 Доступ ко второму уровню иерархии университета (колледжи)
38 Преобразование XML