Перейти на главную страничку сайта (список статей, файлы для скачивания)
В интерактивном режиме MSH работает в глобальном контексте, в котором любые переменные и функции являются доступными везде в пределах оболочки:
MSH> function showA { write-host $a } MSH> $a = 10 MSH> showA 10
Другой пример:
MSH> function doWork { $processes = get-process } MSH> doWork MSH> $processes.Count MSH>
После выполнения функции переменная $processes остаётся неопределенной, и это замечательно: если бы эта переменная хранила важные данные, её значение было бы случайно перезаписано в момент вызова функции. Фактически переменная была определена в локальном контексте (только для функции). При завершении работы функции все переменные локального контекста удаляются.
Поскольку иногда необходимо, чтобы переменные сохранялись и после завершения функции, в которой они определены, MSH имеет синтаксис для работы с переменными в глобальном контексте:
MSH> function doWork { $global:processes = get-process } MSH> doWork MSH> $processes.Count 43
MSH обеспечивает множественные уровни контекста. Когда функция вызвана изнутри другой, вызванная функция видит глобальный контекст и контекст её родителя. В следующем примере используется функция showA, определённая в первом примере этой статьи:
MSH> function setAndShowA { $a = 5; showA } MSH> $a=10 MSH> setAndShowA 5 MSH> $a 10
Сценарии, подобно функциям, выполняются в пределах своих собственных специальных контекстов сценария, которые создаются при запуске сценария и уничтожаются при его завершении. Префикс $script удобен для того, чтобы изменять переменные, которые определены в сценарии вне текущей функции и не являются глобальными переменными:
$script:MyVar = ...
В случаях типа запуска профиля мы не хотим, чтобы сценарий работал в его собственном контексте, а предпочли бы, чтобы он воздействовал на глобальный контекст. В этом случае сценарий запускается с указанием точки перед именем файла. Запуск сценария таким способом предписывает MSH загружать дочерний контекст в родительский в тот момент, когда сценарий завершён. Например, сценарий содержит такую строку:
$a = 20
А так можно увидеть разницу между запуском этого сценария с точкой и без:
MSH> .\test.msh MSH> $a MSH> . .\test.msh MSH> $a 20
Контекст применяется ко всем элементам языка MSH, включая переменные, функции и фильтры. Есть четыре категории контекста: global, local, script и private.
В сеансе MSH создаётся только один глобальный контекст. Глобальные контексты не передаются между различными экземплярами MSH. Время жизни глобального контекста - сессия MSH.
При выполнении функции, фильтра или сценария всегда создаются новые локальные контексты. Новые контексты имеют доступ для чтения (но не для записи) ко всем контекстам родителя, родителя родителя, и так далее, до глобального контекста. Родители не могут читать дочерние контексты. Время жизни локального контекста - текущий блок сценария и любые скрипты/функции, вызванные из него.
При запуске сценария всякий раз создаётся контекст сценария, который уничтожается, когда сценарий заканчивается. Все файлы сценариев подчиняются этому правилу, если они запущены не с точкой. Иначе их контекст загружается в контекст родителя в момент их завершения. Если сценарии запускают друг друга по цепочке, применяются те же самые правила. Время жизни контекста сценария - текущий скрипт и любые скрипты/функции, вызванные из него.
Приватные и локальные контексты очень похожи, но имеют одно различие: определения, сделанные в приватном контексте, не наследуются никакими дочерними контекстами. Время жизни приватного контекста - только текущий блок сценария, но не скрипты/функции, вызванные из него.
Если вы не хотите, чтобы функции наследовали контекст блока, который вызывает их, определите нужные переменные как приватные:
MSH> $private:a = 5 MSH> showA MSH>
Строки в MSH могут находиться как в одинарных, так и в двойных кавычках. Различие между ними видно из следующего примера:
MSH> $myName = "Вася" MSH> "Привет, $myName" Привет, Вася MSH> 'Привет, $myName' Привет, $myName
Одинарные кавычки позволяются в строках, заключенных в двойные кавычки, и наоборот.
Для обращения к сложным переменным типа массивов и хэш-таблиц внутри строк может использоваться специальный синтаксис:
MSH> $arr = @("first","second") MSH> $arr[0] first MSH> "$arr[0]" first second[0] MSH> "$($arr[0])" first
Ещё пример:
MSH> "Текущая дата - $(get-date)" Текущая дата - 01.01.2006 19:16:52
Для ввода служебных символов используется специальный экранирующий символ (`), например:
MSH> "Col 1`tCol 2`tCol 3" Col 1 Col 2 Col 3
Символ (`) указывает, что символ, идущий немедленно после него, должен быть понят буквально, что является полезным, если этот символ имеет специальное значение к MSH, но в данный момент его не нужно использовать этим способом. Например, copy-item my` file1 file2 будет означать копирование файла "my file1" в файл "file2" (т.е. экранирование пробела).
Когда символ (`) используется в пределах строки, MSH заменяет его и символ, следующий за ним, на специальный символ:
`' | Одинарная кавычка. |
`" | Двойная кавычка. |
`` | Акцент. |
`$ | Символ доллара. |
`0 | Null-символ (отличен от $( )). |
`a | Звуковой сигнал (alert). |
`b | BackSpace. |
`f | Перевод страницы. |
`n | Новая строка. |
`r | Возврат каретки. |
`t | Табуляция. |
`v | Вертикальная табуляция. |
Способ присваивания переменной многострочного текста:
MSH> $MultiString = @" >> раз >> два >> "@ >> MSH> $MultiString раз два
Способ присваивания вывода команды переменной:
MSH> $pingTarget="127.0.0.1" MSH> $pingOutput = $(ping $pingTarget)
MSH поддерживает знакомый синтаксис подстановочных знаков, используя символы (?) и (*):
MSH> get-childitem *.msh
Чтобы определить набор символов, любой из которых "подходит", можно применять квадратные скобки [], как в регулярных выражениях, и использовать при необходимости дефис для указания диапазона:
MSH> get-childitem *[a-z].msh
Примечание: чтобы найти файлы, в именах которых попадаются сами символы квадратных скобок, используйте экранирующий символ (`), например: get-childitem default`[12`].htm.
Для получения подробной справки по подстановочным знакам используйте команду get-help about_Wildcard.
Регулярное выражение описывает набор соответствий для строки. Регулярное выражение может выражать две или более строки, соответствующие критериям поиска. Замены отделяются вертикальной чертой (|), как для конвейера. Например, регулярное выражение w3svc|iisadmin|msftpsvc соответствует строкам "w3svc", "iisadmin", "msftpsvc". Квадратные скобки часто используются как сокращение для того, чтобы определить единственный символ из нескольких возможных, например, [aeiou] эквивалентно a|e|i|o|u. Чтобы охватить диапазон, в квадратных скобках может использоваться дефис, например [a-m] означает любой символ в первой половине алфавита.
Различные части регулярного выражения могут группироваться с использованием круглых скобок (скобки могут быть вложены).
Квантификация в регулярных выражениях даёт возможность определить, сколько раз некоторый символ или последовательность символов должна встретиться, чтобы определить соответствие:
* | Нуль или больше раз. |
+ | Один или больше раз. |
? | Один раз. |
{n} | Точно n раз. |
{n,} | Не менее n раз. |
{n,m} | Не менее n раз, и не более m раз. |
Регулярные выражения могут использовать набор специальных символов - сокращений:
. | Любой одиночный символ. |
^ | Начало строки. |
$ | Конец строки. |
\b | Граница слова (например, пробел или перевод строки). |
\d | Цифра (0-9). |
\n | Новая строка. |
\s | Пробельный символ (пробел, табуляция, новая строка и т.д.). |
\t | Табуляция. |
\w | Слово (буквы, цифры и символы подчеркивания). |
Многие из этих специальных символов "инвертируются" с использованием заглавной буквы. Например, \S - не пробельный символ, \W - не слово, и т.д.
Несколько примеров простых регулярных выражений:
(\w*\\)?\w* | Имя пользователя Windows. |
^\d+\.\d+\.\d+\.\d+$ | IP-адрес. |
^{?[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}}?$ | GUID в формате {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. |
Для начала рассмотрим оператор сравнения -eq. Когда он используется со строками, этот оператор производит сравнение без учета регистра:
MSH> "foo" -eq "foo" True MSH> "foo" -eq "bar" False MSH> "foo " -eq "foo" False MSH> "foo" -eq "FOO" True
Оператор -like позволяет использовать подстановочные знаки *, ? и []:
MSH> "foo" -like "foo" True MSH> "foobar" -like "foo*" True MSH> "foobar" -like "*ba?" True MSH> "gray" -like "gr[ae]y" True
Чтобы проверить соответствие с учетом регистра, используется оператор -clike. Имеются и обратные команды -notlike и -cnotlike.
MSH исполняет регулярные выражения с помощью оператора -match. Также существуют операторы -cmatch, -notmatch и -cnotmatch. Примеры:
MSH> "ipv6.exe" -match ".*exe" True MSH> "ipv6.exe" -match ".*\d{1}.*exe" True MSH> "ipv6.exe" -match ".*\d{2}.*exe" False MSH> get-childitem | where-object { $_ -match ".*\d{2}.*exe" }
Создание и проверка GUID'а:
MSH> $guidRegex = "^{?[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}}?$" MSH> $myGuid = [System.Guid]::NewGuid( ).ToString( ) MSH> $myGuid b08924c0-b76a-445e-9627-184b13375a0e MSH> $myGuid -match $guidRegex True
Получение и проверка IP-адреса:
function get-ipaddress { $hostname = [System.Net.Dns]::GetHostName() $hosts = [System.Net.Dns]::GetHostByName($hostname) $hosts.AddressList[0].ToString() } $ipRegex = "^\d+\.\d+\.\d+\.\d+$" $myIP = get-ipaddress $myIP $myIP -match $ipRegex
Подробнее о регулярных выражениях можно почитать на сайте Microsoft.
Существуют два типа ошибок, которые могут произойти при обработке команд. Первый тип, non-terminating error, указывает, что произошла некоторая ошибка, но выполнение всё ещё может продолжаться. Пример такой ошибки - проблема доступа, которая происходит при попытке прочитать защищенный ресурс, или попытка записать файл только для чтения. Напротив, terminating error означает состояние, в котором выполнение не может продолжиться, и команда завершается.
Ядро системы обработки ошибок определяется ключевым словом TRap. Это ключевое слово сопровождается блоком сценария, который содержит команды, определяющие, что необходимо сделать, когда происходит ошибка. Также существуют некоторые дополнительные "вездесущие" параметры команд, которые используются, чтобы определить то, что должен сделать команд-лет в случае ошибки.
Пример с делением на нуль:
MSH> 100/0 Попытка деления на нуль. At line:1 char:5 + 100/0 <<<< MSH> $error[0] Попытка деления на нуль.
Всякий раз, когда во время выполнения программы происходит ошибка, MSH автоматически обновляет специальный массив $error с информацией о проблеме. Самая недавняя ошибка находится в первом слоте [0].
Простейший обработчик ошибок:
trap { "Ой! Проблема: " + $_ } $a = 0 100/$a
Предположим, что мы имеем папку-источник, которая содержит файлы a.txt, b.txt, и c.txt, и планируем скопировать их в папку назначения, которая уже содержит копию a.txt с флагом read-only:
mkdir source "content" > source\a.txt "content" > source\b.txt "content" > source\c.txt mkdir dest copy source\a.txt dest\a.txt attrib +r dest\a.txt
При выполнении следующей команды копирования произойдёт ошибка:
copy-item source\* dest
Однако, файлы b.txt и c.txt будут скопированы, несмотря на эту ошибку. Поведение команд-лета перед лицом ошибки типа non-terminating error управляется опцией -ErrorAction. По умолчанию, она принимает значение Continue, которое инструктирует команд-лет уведомлять пользователя о проблеме и продолжать обработку. Используя другую установку ErrorAction, можно изменить поведение команд-лета, например, попросить его в случае ошибки выдавать запрос на продолжение:
copy-item -ErrorAction Inquire source\* dest
Следующий сценарий предписывает команд-лету copy-item прекратить работу в случае неудачи, и осуществляет 10 повторных попыток скопировать файл:
$retryCount=10 while ($retryCount -gt 0) { $success = $true trap { $script:retryCount-- $script:success = 0 "Retrying..." continue } copy-item -ErrorAction Stop source\* dest if ($success) { $retryCount = 0 } } "Done"
Ключевое слово trap может сопровождаться типом ошибки в квадратных скобках, чтобы указать, что обработчик должен быть выполнен, только если ошибка имеет указанный тип:
trap [DivideByZeroException] { "Деление на нуль" break }
В пределах блока trap всегда доступна специальная переменная $_. Блоки trap подчинены правилам видимости данных так же, как и переменные. Родительские контексты никогда не будут вызывать обработчики trap любых дочерних записей, но ошибка в дочернем контексте (типа функции, фильтра или цикла) заставят передавать выполнение к самому близкому блоку trap. Каждый контекст может содержать несколько блоков trap. Помещая инструкцию continue в конце блока trap (как последнюю команду перед закрывающей фигурной скобкой), мы инструктируем MSH продолжить обработку вместо того, чтобы закончить выполнение.
Опция ErrorAction имеет несколько возможных параметров. В конвейере допустимо использовать различные параметры настройки ErrorAction для различных стадий:
Stop | Аварийное прекращение работы при неудаче. |
Continue | Генерация ошибки и продолжение работы. |
Inquire | Запрос о продолжении. |
SilentlyContinue | Продолжение работы без генерации ошибки. |
Можно изменить заданное по умолчанию значение ErrorAction. MSH фактически берёт это значение из глобальной переменной $ErrorActionPreference. Вы можете добавить строку типа $ErrorActionPreference = "Inquire" к вашему профилю.
Перейти на главную страничку сайта (список статей, файлы для скачивания)
© 2007 http://www.script-coding.com При любом использовании материалов сайта обязательна ссылка на него как на источник информации, а также сохранение целостности и авторства материалов.