Кто, если не ты? Когда, если не сейчас?
В предыдущей части мы научились запускать PowerShell, разобрались с политикой выполнения сценариев. Поняли, что такое командлеты, знаем, как передавать их по конвейеру и как получить их свойства. Узнали, что PowerShell имеет огромный Help.
В этой части мы разберёмся с переменными, узнаем, что они за типы и как к ним обращаться, как их сравнивать и выводить всевозможными способами. Обязательно разберёмся с циклами и напишем несколько функций.
← Перейти к I части
Введение
Начать я хочу с ответов на вопросы, возникшие в первом нашем с Вами Jump Start'е:
Если бы мне пришлось охарактеризовать PowerShell в трёх словах, я бы сказал: это среда упрощающая администрирование, помогающая создать инструменты для автоматизации и управления.
Изучить PowerShell точно стоит, если ты администрируешь Windows Server и серверное ПО от Microsoft. Возьмём, к примеру, один из популярнейших продуктов Microsoft Exchange Server — и тут же натыкаешься на PowerShell консоль Exchange Management Shell.
Зная PoSh ты без труда сможешь сделать любую нужную выгрузку данных, настроить контроль за любыми процессами системы, отправлять отчёты, создавать пользователей, решать их проблемы…
Вы студент? Напишите себе своё первое приложение, которое будет решать квадратное уравнение.
Или, например, изучите парсинг и сделайте своё приложение для скачивания музыки или красивых видео из youtube.
Всё зависит от тебя и твоей фантазии. Посмотрите сюда, PowerShell можно даже научить разговаривать.
Правда, не каждый имеет время на просмотр 12-15 часового курса и не каждый может так воспринимать информацию.
Здесь я пробую дать базовые знания с которыми можно будет успешно продолжить развивать свои умения безгранично дальше.
Переменные
- Переменная в PowerShell начинается со знака $
(в Евросоюзе со знака €)и в названии может содержать любые буквы, цифры и символ подчёркивания. - Чтобы назначить переменной значение, достаточно его ей присвоить знаком "=". Чтобы вывести значение переменной, можно просто написать эту переменную. Вывод информации мы разберём по тексту ниже.
$var = 619 $var
- Над числами можно производить арифметические операции, строки можно складывать. Если к строке прибавить число, число автоматически преобразуется в строку.
$a = 1 $b = 2 $c = $a + $b $c #c = 3 $str = "Хабра" $str = $str + "хабр" $str #str = Хабрахабр $str = $str + 2014 $str #str = Хабрахабр2014
- Если нам надо узнать, какой тип имеет та или иная переменная, можно воспользоваться методом GetType()
$s = "Это строка?" $s.GetType().FullName
- Тип переменной PowerShell определяет автоматически или его можно назначить вручную.
$var = "one" [string]$var = "one"
PowerShell использует типы данных Microsoft .NET Framework. Рассмотрим основные:
Тип / .NET класс Описание [string] System.String
Строка $var = "one"
[char] System.Char
Символ $var = [char]0x263b
[bool] System.Boolean
Булево. Может иметь значение $true или $false. $bvar = $true
[int] System.Int32
32-разрядное целое число $i = 123456789
[long] System.Int64
64-разрядное целое число $long_var = 12345678910
[decimal] System.Decimal
128 битное десятичное число. Буква d на конце числа обязательна $dec_var = 12345.6789d
[double] System.Double
8-байтное десятичное число с плавающей точкой [double]$double_var = 12345.6789
[single] System.Single
32 битное число с плавающей точкой [single]$var = 123456789.101112
[DateTime] System.DateTime
Переменная даты и времени. $dt_var = Get-Date
[array] System.Object[]
Массив. Индекс элементов массива начинается с 0 — чтобы обратиться к первому элементу массива $mas, следует написать $mas[0]. $mas = "one", "two", "three";
Для добавления элемента к массиву, можно записать
$mas = $mas + "four"
Каждый элемент массива может иметь свой тип
$mas[4] = 1
[hashtable] System.Collections.Hashtable
Хеш-таблицы. Различие между хэш-таблицами и массивами в том, что в массивах используются индексы, а в хэш-таблице именованные ключи. Хеш-таблицы строятся по принципу: @{ ключ = «значение» } $ht = @{odin="one"; dva="two"; tri="three"}
Чтобы добавить элемент к хеш-таблице, можно или присвоить ей тот ключ, которого ещё нет, или воспользоваться методом Add(). Если присваивание делать к существующему ключу — значение ключа изменится на присваиваемое. Для удаления элемента из хеш-таблицы есть метод Remove().
$ht.Add("chetyre", "four") $ht.pyat = "five" $ht.Remove("dva")
Вы наверняка уже поняли, что в переменную можно записать не только какое-то определённое значение и заметили в таблице класс System.Object[]. В переменную так же можно записать вывод любого командлета.
Разберём боевую задачку: требуется узнать IP-адрес и MAC-адрес нескольких компьютеров в сети. Имена компьютеров domain-comp1, domain-comp2. Вариант решения под спойлером:
$MAC = Get-WmiObject -ComputerName domain-comp1, domain-comp2 -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=True | Select-Object -Property * | SELECT PSComputerName, @{Name="IPAddress";Expression={$_.IPAddress.get(0)}}, MACAddress, Description
$MAC
Что происходит:
Мы записываем в переменную $MAC результат от выполнение командлета Get-WmiObject, с помощью которого передаём WMI запрос на компьютеры, указанные в параметре -computername и возвращаем нужную нам информацию из класса Win32_NetworkAdapterConfiguration.
Обратите внимание, если надо получить IP-адрес и MAC-адрес текущего компьютера, то вместо имён компьютеров, параметру -computername мы передадим точку. И, давайте, в следующим примере сохраним результат в файл D:comp_mac_ip.csv:
$MAC = Get-WmiObject -ComputerName . -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=True | Select-Object -Property * | SELECT PSComputerName, @{Name="IPAddress";Expression={$_.IPAddress.get(0)}}, MACAddress, Description
$MAC | Export-Csv D:comp_ip_mac.csv -Encoding UTF8
Область действия переменных
Область действия переменной в PowerShell может быть либо локальной, либо глобальной. По умолчанию переменная имеет локальную область действия и ограничена областью действия, например, доступна только в функции или только в текущем сценарии. Глобальная переменная действует во всём текущем сеансе PowerShell. Для того, чтобы обозначить глобальную переменную, достаточно написать следующую конструкцию: $Global: переменная = значение
$Global:var = 12
И ещё фишка по теме переменных… Как-то, обсуждая с коллегой 1С и его русскоязычную среду программирования, задались вопросом:
И да, действительно:
function привет() { "Привет, $env:USERNAME. Может не стоит писать на русском?"
Start-Sleep 3
"Открыть Хабр?"
}
function открывай() { & "C:Program FilesInternet Exploreriexplore.exe" http://habrahabr.ru/post/242425/ }
Операторы сравнения и логические операторы
Операторы сравнения и логические операторы проверяют равенство или соответствие между двумя значениями.
- При выполнении условия, конструкция сравнения всегда возвращает логическое значение $true или $false, если условие ложь.
В таблице ниже приведены операторы сравнения:
Оператор | Описание | Пример |
---|---|---|
-eq | Equal / Равно (=) |
|
-ne | Not equal / Не равно (<>) |
|
-gt | Greater than / Больше (>) |
|
-ge | Greater than or equal / Больше или равно (>=) |
|
-lt | Less than / Меньше (<) |
|
-le | Less than or equal / Меньше или равно (<=) |
|
-like | Сравнение с учётом символа подстановки |
|
-notlike | Сравнение с учётом не соответствия символа подстановки |
|
-contains | Содержит ли значение слева значение справа |
|
-notcontains | Если значение слева не содержит значение справа, получим истину |
|
-match | Использование регулярных выражений для поиска соответствия образцу |
|
-notmatch | Использование регулярных выражений для поиска несоответствия образцу |
|
-replace | Заменяет часть или все значение слева от оператора |
|
Разберём пример. В примере мы формируем путь до возможного профиля пользователя на удалённом компьютере в зависимости от операционной системы. Решение под спойлером:
#Путь к профилю на удалённом компьютере
Function UProfile ($UCompName, $ULogin) {
[string]$CompOS = Get-WmiObject -ComputerName $UCompName -Class Win32_OperatingSystem | SELECT Caption #Получаем заголовок операционной системы компьютера
if ($CompOS -match "Windows 7") { #Если в заголовке содержится "Windows 7"
[string]$LinkUserProfile = "\$UCompNamed$users$ULogin" #Получаем такой путь
$LinkUserProfile
} elseif ($CompOS -match "Windows XP") { #Если в заголовке содержится "Windows XP"
[string]$LinkUserProfile = "\$UCompNamed$Documents and Settings$ULogin" #Получаем такой путь
$LinkUserProfile
}
}
UProfile domain-comp1 Administrator #функция имя-компьютера логин-пользователя
Да, здесь мы не проверяем, существует ли профиль. Но можно и проверить. Для этого добавим ещё одно условие, в котором будем проверять командлетом Test-Path существование пути:
#Путь к профилю на удалённом компьютере
Function UProfile ($UCompName, $ULogin) {
[string]$CompOS = Get-WmiObject -ComputerName $UCompName -Class Win32_OperatingSystem | SELECT Caption #Получаем заголовок операционной системы компьютера
if ($CompOS -match "Windows 7") { #Если в заголовке содержится "Windows 7"
[string]$LinkUserProfile = "\$UCompNamed$users$ULogin" #Получаем такой путь
} elseif ($CompOS -match "Windows XP") { #Если в заголовке содержится "Windows XP"
[string]$LinkUserProfile = "\$UCompNamed$Documents and Settings$ULogin" #Получаем такой путь
}
if (Test-Path $LinkUserProfile) { $LinkUserProfile } else { "Профиль $ULogin не существует на компьютере $UCompName" } #Проверяем существование профиля
}
UProfile domain-comp1 Administrator #функция имя-компьютера логин-пользователя
Кстати, регулярные выражение в PowerShell очень хорошо описал Xaegr в своём блоге. Стоит того, чтобы потратить пару часов на прочтение и постичь умение написания regular expressions.
- Можно дополнительно задать условие, если при сравнении следует учитывать регистр. Для этого следует перед оператором подставить букву "c"
$str1 = "Habr" $str2 = "habr" $str1 -ceq $str2 #$false
- Можно использовать несколько операторов сравнения, применяя логические операторы. Логические операторы перечислены в таблице ниже:
Оператор | Описание | Пример |
---|---|---|
-and | Логическое и |
|
-or | Логическое или |
|
-not | Логическое не |
или
|
Пара слов про if… elseif и else
if ( условие1-верно ) { выполняем-код } #если условие 1 верно, выполняем код, если нет - идём дальше
elseif ( условие2-верно ) { выполняем-код } #необязательное условие: иначе, если условие 2 верно, выполняем код
else { выполняем-код } #необязательное условие: если прошлое условие не верно, выполняем код
Всё совсем просто. Если условие верно, мы выполняем следующий за условием код в фигурных скобках. Если условие не верно, то мы пропускаем выполнение и смотрим, продолжается ли у нас условие дальше.
Если находим elseif — проверяем новое условие и так же, в случае успеха, выполняем код, иначе, снова смотрим, есть ли продолжение в виде elseif или else.
Если условие выполняется, то код выполняется и ветка elseif или else пропускается.
$str = ""
if ( 1 -gt 2 ) { $str = "Апельсин" }
elseif ( $str -eq "Апельсин" ) { $str }
else { $str = "Яблоко"; $str }
Вывод информации
Рассмотрим несколько основных вариантов вывода информации на экран:
- Запись в файл, используя Out-File
$str = "Hello Habr!" $str | Out-File D:out_test1.txt
или, как мы говорили в I части, использовать знак ">"
$str = "Hello Habr!" $str > D:out_test2.txt
- Экспорт данных в .csv файл, используя Export-Csv
$p = Get-Process $p | SELECT Name, Path | Export-Csv -Path D:out_test3.csv
- Запись в файл HTML, используя ConvertTo-Html
$h = Get-Process $h | ConvertTo-Html -Property Name, Path > D:out_test4.html & D:out_test4.html #Откроем файле после формирования
Работать с HTML выводом на самом деле очень приятно. Имея навыки web-программирования можно добавить стилей и на выходе получить очень симпатичные отчёты.
Прочитать файл нам поможет уже знакомый нам командлет Get-Content
Get-Content D:out_test1.txt
Циклы
Циклы в PowerShell мало чем отличаются от циклов в других языках. Почти всё как и везде:
Do While
Делать до тех пор, пока условие верно
$x = 10
do
{
$x
$x = $x - 1
}
while ($x -gt 0)
Do Until
Цикл, который повторяет набор команд, пока выполняется условие
$x = 0
do
{
$x
$x = $x + 1
}
until ($x -gt 10)
For
Цикл, который повторяет одинаковые шаги определённое количество раз
for ($i = 0; $i -lt 10; $i++)
{
$i
}
ForEach
Цикл по коллекции объектов
$collection = "Имя-Компьютера1", "Имя-Компьютера2", "Имя-Компьютера3"
foreach ($item in $collection)
{
$item
}
Пишем функции
- Функции в PowerShell имеют следующую структуру:
function имя-функции ([параметр1, ..., параметрN]) { тело-функции }
- Функции не обязательно должны возвращать результат.
- При вызове функции, все параметры разделяются пробелами.
Например, функция для получения квадрата числа, на PowerShell будет выглядеть так:
function sqr ($a)
{
return $a * $a
}
sqr 2 #Результат: 4
И на последок, пример функции, которая поможет нам выполнять транслитерацию. В этом примере как раз всё то, что мы сегодня рассматривали:
#Транслитерация
function Translit ([string]$inString)
{
$Translit = @{ #Создаём хеш-таблицу соответствия символов
[char]'а' = "a"
[char]'А' = "A"
[char]'б' = "b"
[char]'Б' = "B"
[char]'в' = "v"
[char]'В' = "V"
[char]'г' = "g"
[char]'Г' = "G"
[char]'д' = "d"
[char]'Д' = "D"
[char]'е' = "e"
[char]'Е' = "E"
[char]'ё' = "yo"
[char]'Ё' = "Yo"
[char]'ж' = "zh"
[char]'Ж' = "Zh"
[char]'з' = "z"
[char]'З' = "Z"
[char]'и' = "i"
[char]'И' = "I"
[char]'й' = "j"
[char]'Й' = "J"
[char]'к' = "k"
[char]'К' = "K"
[char]'л' = "l"
[char]'Л' = "L"
[char]'м' = "m"
[char]'М' = "M"
[char]'н' = "n"
[char]'Н' = "N"
[char]'о' = "o"
[char]'О' = "O"
[char]'п' = "p"
[char]'П' = "P"
[char]'р' = "r"
[char]'Р' = "R"
[char]'с' = "s"
[char]'С' = "S"
[char]'т' = "t"
[char]'Т' = "T"
[char]'у' = "u"
[char]'У' = "U"
[char]'ф' = "f"
[char]'Ф' = "F"
[char]'х' = "h"
[char]'Х' = "H"
[char]'ц' = "c"
[char]'Ц' = "C"
[char]'ч' = "ch"
[char]'Ч' = "Ch"
[char]'ш' = "sh"
[char]'Ш' = "Sh"
[char]'щ' = "sch"
[char]'Щ' = "Sch"
[char]'ъ' = ""
[char]'Ъ' = ""
[char]'ы' = "y"
[char]'Ы' = "Y"
[char]'ь' = ""
[char]'Ь' = ""
[char]'э' = "e"
[char]'Э' = "E"
[char]'ю' = "yu"
[char]'Ю' = "Yu"
[char]'я' = "ya"
[char]'Я' = "Ya"
}
$TranslitText = ""
foreach ($CHR in $inCHR = $inString.ToCharArray())
{
if ($Translit[$CHR] -cne $Null)
{ $TranslitText += $Translit[$CHR] } #аналог записи $TranslitText = $TranslitText + $Translit[$CHR]
else
{ $TranslitText += $CHR }
}
return $TranslitText
}
Translit Хабрахабр #Вывод: Habrahabr
Послесловие
Теперь мы знаем достаточно информации, чтобы начать погружаться в PowerShell ещё глубже. В этой части мы встретились с переменными, типами данных, разобрались с выводом информации, операторами сравнения, циклами… Посмотрите, ведь начать, оказывается, не так уж и сложно!
Сохраняй спокойствие и учи PowerShell.
Продолжение следует...
Дополнительная информация
- Jump Start в PowerShell (часть I);
- Скачать PowerShell v.4 бесплатно без регистрации;
- Замечательный курс на MVA: Расширенные возможности и написание скриптов в PowerShell 3.0 (Jump Start). Мой совет — посмотрите первые 3 блока, окунитесь в язык, попробуйте повыполнять какие-нибудь задачи и через недельку смотрите оставшиеся блоки. Русские субтитры;
- Видео в тему на TechDays;
Галерея скриптов PowerShell на Technet;
Блог разработчиков PowerShell.
Автор: bgelov