Обзор технологии Microsoft Windows PowerShellMicrosoft ® 1 Назначение PowerShell 2 Установка Windows PowesShell 6 Назначение PowerShell 7



Скачать 13.55 Mb.
страница27/27
Дата29.11.2016
Размер13.55 Mb.
Просмотров5659
Скачиваний0
ТипОбзор
1   ...   19   20   21   22   23   24   25   26   27

Отладка


Логические ошибки, возможно, являются самыми сложными в исправлении. Обычно их нельзя предусмотреть заранее, и они не всегда влекут за собой уведомление об ошибке. Просто в результате логической ошибки скрипт работает не так, как было запланировано. Цель отладки скрипта – выявить причину возникновения логических ошибок, исправить их и протестировать результат.

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

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

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


Отладочный вывод


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

Оболочка не создает трассировочные сообщения автоматически. Чтобы получить их, необходимо использовать в сценарии командлет Write-Debug. Например, каждый раз, когда вы меняете значение переменной, вы должны прописывать новое значение таким образом:



$var = Read-Host "Enter a computer name"

Write-Debug "`$var contains $var

Обратите внимание, что в данном примере использования Write-Debug переменная и ее содержание помещены в двойные кавычки. Однако в первом случае переменная указана без знака $. В результате имя переменной отобразится как есть, вслед за ним идет содержимое переменной и ее значение. Выходные данные такой отладки весьма полезны, так как содержат имя переменной и ее значение. Также следует использовать Write-Debug везде, где скрипт принимает решение. Например, рассмотрим следующий отрывок:



If ($var –notlike "*srv*") {

Write-Host "Computer name is not a server"

}

You might modify this as follows:

If ($var –notlike "*srv*") {

Write-Debug "$var does not contain ‘srv’"

Write-Host "Computer name $var is not a server"

} else {

Write-Debug "$var contains ‘srv’"

}

Обратите внимание, что был добавлен блок Else, поэтому скрипт будет генерировать трассировочные сообщения независимо от того, какое логическое решение будет принято. По умолчанию оболочка скрывает выходные данные Write-Debug. Чтобы они отображались, поместите переменную $DebugPreference в начало скрипта:



$DebugPreference = 'Continue'

Теперь выходные данные Write-Debug будут отображаться. Когда вы закончите отладку скрипта, удалять команды Write-Debug будет не нужно. Вместо этого снова скройте их выходные данные:



$DebugPreference = 'SilentlyContinue'

Таким образом, команда Write-Debug останется в скрипте на тот случай, если в дальнейшем она снова понадобится для отладки.

На заметку: Выходные данные Write-Debug отличаются от обычных выходных данных в окне консоли Windows PowerShell. Сторонние скриптовые редакторы могут перенаправить эти данные в другую панель, окно или страницу, позволяя таким образом отделить трассировочные сообщения от других данных.

Пошаговый отладчик


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

Set-PSDebug –step

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



Set-PSDebug –off

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


Контрольные точки


Одним из недостатков пошагового отладчика является отсутствие возможности пропускать те части скрипта, в корректной работе которых вы не сомневаетесь. Если ваш скрипт состоит из 200 строк, и вы знаете, что проблема находится где-то в конце, нажимать Yes столько раз подряд довольно утомительно.

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

Условия контрольных точек могут быть следующими:

• Остановить выполнение сценария при достижении определенной строки.

• Остановить выполнение сценария при чтении определенной переменной.

• Остановить выполнение сценария, когда определенная переменная изменяется или пишется.

• Остановить выполнение сценария, когда определенная переменная читается или пишется.

• Остановить выполнение сценария при выполнении опрделенной команды или функции.

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

Управление контрольными точками осуществляется с помощью командлетов:

• Set-PSBreakpoint – создание нового условия контрольной точки.

• Remove-PSBreakpoint – удаление условия контрольной точки.

• Disable-PSBreakpoint - прекратить действие условия контрольной точки без его удаления.

• Enable-PSBreakpoint – возобновить действие остановленного условия контрольной точки.

• Get-PSBreakpoint – извлечь одно или несколько условий контрольной точки.

Контрольные точки позволяют вам задавать условия, при которых выполнение сценария будет приостановлено (или будет произведено другое действие).


Отладка в ISE


Отладчик Windows PowerShell обеспечивает базовую визуальную поддержку для отладки, в первую очередь, в сочетании с контрольными точками. Визуальных средств для создания контрольной точки нет. Однако когда вы создаете контрольную точку по номеру строки для сценария (используя параметр –script командлета Set-PSBreakpoint), ISE отображает эту контрольную точку внутри скрипта, подчеркивая соответствующую строку. Когда вы запускаете этот скрипт, ISE позволяет наводить курсор мышки на имена переменных, чтобы увидеть их содержимое.

Модуляризация


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

Модуляризация предназначена для создания полезных, независимых компонентов для многократного использования. Цель модуляризации – ускорить процесс написания скриптов, позволяя повторно использовать готовые фрагменты из предыдущих проектов. В Windows PowerShell базовой формой модуляризации является функция. Вы уже встречались с понятием функции ранее – сейчас мы рассмотрим их назначение более подробно.

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

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

Вы можете воспринимать командлеты как особую форму модуляризации, хотя настоящие командлеты требуют знания.NET Framework.

Для выполнения своей задачи функция должна получить особенный вид входящих данных. Функция никогда не должна пытаться получить доступ к информации, находящейся за пределами себя самой – это во многом снизит возможность ее повторного использования. Например, предположите, что вы имеете скрипт, содержащий функцию Get-ServerName. Если предполагается, что эта функция может читать переменные, содержащиеся в родительской оболочке, любой скрипт, в котором используется эта функция, должен содержать соответствующие переменные. Такая зависимость усложняет многократное использование функции в разных сценариях. Однако, поддерживая автономность функции, вы сможете с легкостью использовать ее в самых разных ситуациях.

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

Базовые функции


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

Function Do-Something {

# function code goes here

}

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



Do-Something

Командлет Write-Output – это верный способ извлечения выходных данных из функции. Этот командлет с псевдонимом Write отправляет объекты в конвейер, где они могут быть использованы другими командлетами. Существует три способа использования Write-Output. Предположим, вы имеете выходные данные в виде переменной с именем $var. Все три примера будут идентичными с функциональной точки зрения:



Write-Output $var

Write $var

$var

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



Return $var

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

Не используйте Write-Host для извлечения выходных данных из функции. Write-Host не передает данные в конвейер, напротив, он отправляет текст напрямую в окно консоли. Текст нельзя передать по конвейеру другому командлету, а значит, возможность повторного использования функции ограничивается.

Параметризованные функции


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

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



Function Do-Something ($computername,$domainname) {

# function code goes here

}

На заметку: Старайтесь указывать имя функции в виде «глагол-существительное в единственном числе», так же, как это делается с командлетами. Однако следите за тем, чтобы случайно не присвоить функции имя существующего командлета.

Второй, и более предпочтительный способ определения входящих параметров функции выглядит так:

Function Do-Something {

Param(

$computername,

$domainname

)

# function code goes here

}

Этот метод предпочтительнее потому, что он легче читается, а также потому, что здесь используется условное обозначение, применяемое оболочкой для сохранения функции в памяти. Обратите внимание, что жестких правил форматирования здесь нет – вы также можете использовать следующую форму:



Function Do-Something {

Param($computername,$domainname)

# Function code goes here

}

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



Function Do-Something {

Param(

[string]$computername = 'localhost',

[string]$domainname = 'contoso.com'

)

# function code goes here

}

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



Function Do-Something {

Param(

[string]$computername = $(Read-Host 'Computer name'),

[string]$domainname = $(throw 'Domain name required.')

)

# function code goes here

}

Когда вы запускаете параметризованную функцию, вы можете передавать входящие значения с помощью:



Do-Something localhost 'contoso.com'

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



Do-Something –domainname contoso –computername localhost

Передача данных конвейером


Итак, вы узнали, как передать входящие значения функции с помощью параметров. Но функции также могут принимать данные по конвейеру. В нормальной параметризованной функции оболочка автоматически входящие по конвейеру данные в специальную переменную, которая называется $input. Указывать $input в качестве параметра не нужно. Однако имеет смысл перечислить элементы в $input, так как зачастую она содержит несколько объектов. Для этого лучше всего использовать конструкцию ForEach. Например:

function Do-Something {

param (

$domain = 'contoso.com'

)

foreach ($computer in $input) {

write "Computer $computer is in domain $domain"

}

}

'localhost','server1' | do-something -domain adatum

Обратите внимание, что входящие по конвейеру данные о двух именах компьютера помещаются в $input, тогда как "adatum" помещается в стандартный параметр $domain.

Это лишь один из способов принятия функцией входящих данных по конвейеру. Более эффективным и легким способом является использование фильтров.

Функции-фильтры


Функции-фильтры предназначены специально для приема входящих данных из конвейера. Такая функция включает в себя три именованных скриптовых блока:

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

• PROCESS: этот блок выполняется один раз для каждого объекта, входящего по конвейеру. Внутри блока специальная переменная $_ содержит текущий объект.

• END: этот блок выполняется один раз, после того как все входящие объекты были обработаны. Его можно использовать для завершения работы, например, для закрытия базы данных.

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

function Do-Something {

param (

$domain = 'contoso.com'

)

BEGIN {}

PROCESS {

$computer = $_

write "Computer $computer is in domain $domain"

}

END {}

}

'localhost','server1' | do-something -domain adatum

Скриптовый блок PROCESS обычно работает так же, как встроенная конструкция ForEach, автоматически перечисляя входящие объекты, и помещая каждый объект по очереди в переменную $_. Обратите внимание, что обычные параметры тоже поддерживаются.


самостоятельное конструирование выходных данных


Функции-фильтры, с которыми вы только что познакомились, запускали команды Windows PowerShell и позволяли этим командам помещать выходные данные в конвейер. Таким образом, выходные данные этих команд превращались в выходные данные функций. Например, в предыдущих примерах сюда входили одно или два обращения к Get-WmiObject.

Windows PowerShell не всегда хорошо справляется с отображением выходных данных, когда в конвейере содержится несколько разных типов объектов, например, Win32_OperatingSystem и Win32_BIOS одновременно. Одним из способов исправления ситуации может стать самостоятельное конструирование выходных данных. Например, вы можете вывести текст и сформировать заголовки столбца, а затем заполнить каждую строку выходными данными. Windows PowerShell даже предлагает специального оператора форматирования –f, который упрощает процесс создания данных такого типа.

В двух предыдущих примерах выходными данными являлся текст, точнее, объекты String. Проблема здесь заключается в том, что текст сложно использовать повторно. Например, вам может понадобиться вывести данные в файл CSV, а не в текстовую экранную таблицу. Используя в качестве отправной точки два вышеописанных подхода, вы будете вынуждены переписывать часть функции, чтобы вывести данные в файл CSV. А если позже вам понадобятся выходные данные в формате XML, вы будете переписывать ее снова.

Как вы уже знаете, Windows PowerShell – это объектоориентированная оболочка, которая работает с объектами гораздо лучше, чем с текстом. В двух предыдущих примерах извлекались два класса WMI: Win32_OperatingSystem и Win32_BIOS. Поскольку это два разных класса, оболочка не может просто отобразить их в одной строчке таблицы – по крайней мере, с использованием средств форматирования, предлагаемых по умолчанию. Решением может стать вывод данных в виде текста, но, как мы знаем, это не лучший способ для Windows PowerShell.

Еще одним способом скомбинировать информацию разных типов может стать создание пустого пользовательского объекта:

$obj = New-Object PSObject

"PSObject" – это очень простой объект, который выступает в роли пустого, чистого холста или полотна. Ему можно придавать любые свойства. Например, свойство ComputerName добавляется следующим образом:



$obj | Add-Member NoteProperty ComputerName $computername

Таким образом добавляется новое свойство типа NoteProperty. NoteProperty – это статическое значение, придаваемое объекту. Новое свойство NoteProperty называется ComputerName, а его значением может быть все, что вы поместите в переменную $computername.

Вы можете добавлять свойства до тех пор, пока объект не примет всю необходимую вам информацию. Затем вы отправляете этот пользовательский объект в конвейер:

Write $obj

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


Разные способы решения


По мере того, как вы будете изучать примеры использования Windows PowerShell из разных источников, в том числе, из Интернета, вы все чаще будете осознавать, что одну и ту же задачу можно выполнить разными способами.

Так, в предыдущем примере вы видели, как с помощью New-Object и Add-Member можно создать новый пользовательский объект. Еще одним подходом является использование Select-Object для придания пользовательских свойств новому пустому объекту:



function Get-Inventory {

PROCESS {

$computer = $_

$os = gwmi win32_operatingsystem -comp $computer

$bios = gwmi win32_bios -comp $computer

$obj = new-object psobject

$obj | select @{Label='ComputerName';Expression={$computer}},

@{Label='SPVersion';Expression={$os.servicepackmajorversion}},

@{Label='BIOSSerial';Expression={$bios.serialnumber}},

@{Label='BuildNo';Expression={$os.buildnumber}}

}

}

gc names.txt | get-inventory

Нельзя сказать, что какой-то один из этих подходов является верным – они оба работают и оба обеспечивают одни и те же результаты. Так что можете смело использовать тот, который кажется вам более удобным. Когда вы лучше познакомитесь с работой Windows PowerShell, вы поймете, что многие задачи можно выполнить с помощью одной-единственной команды, хотя эта команда может быть довольно сложной. Например, всю функцию Get-Inventory, показанную ранее, можно заменить одной сложной командой:



gwmi win32_operatingsystem -computer (gc names.txt) |

select @{Label='ComputerName';Expression={$_.__SERVER}},

@{Label='BuildNo';Expression={$_.BuildNumber}},

@{Label='SPVersion';Expression={$_.ServicePackMajorVersion}},

@{Label='BIOSSerial';Expression={

(gwmi win32_bios -comp $_.__SERVER).serialnumber

}}

Здесь первым запускается командлет Get-WmiObject. Его параметр –computerName получает выходные данные Get-Content, который читает текстовый файл, содержащий по одному имени компьютера в каждой строчке. WMI объект передается командлету Select-Object.

Первые три элемента в Select-Object создают пользовательские свойства объекта, которые используют свойства из Win32_OperatingSystem WMI объекта. Смысл этого – обеспечить пользовательские имена свойств, такие как ComputerName и BuildNo вместо того, чтобы использовать родные имена свойств класса WMI. Последний элемент в Select-Object создает пользовательское свойство, которое называется BIOSSerial. Это выражение свойства в действительности выполняет второй командлет Get-WmiObject для извлечения класса Win32_BIOS. Имя компьютера, передаваемое в этот Get-WmiObject, будет свойством __SERVER первого WMI объекта – это свойство содержит имя компьютера. Обратите внимание, что вся команда Get-WmiObject помещена в скобки – это заставляет оболочку выполнять команду, а скобки обозначают объект, который получится на выходе. Вслед за скобками идет точка, которая указывает на то, что мы хотим получить доступ к одному из элементов объекта, а затем имя этого элемента SerialNumber. Конечным результатом является то, что свойство SerialNumber объекта Win32_BIOS помещается в пользовательское свойство BIOSSerial в Select-Object.

Конечно, это сложная команда, но она наглядно демонстрирует, что Windows PowerShell позволяет выполнять сложные задачи без формального написания скриптов и программирования. Для прочтения и, тем более, написания такой команды, однако, требуется некоторый опыт. Поэтому вы вправе выбрать для себя такой способ работы, который вам кажется проще.


Расширенные функции


Расширенная функция является чуть более «продвинутой» по сравнению с функцией-фильтром. Точнее говоря, расширенная функция – это функция-фильтр, которая имеет дополнительные атрибуты для параметров, которые принимают входящие данные. За счет этих атрибутов расширенные функции выглядят и ведут себя практически так же, как командлеты, написанные на языке .NET Framework. Так указывается функция и параметр для очень простой расширенной функции:

function Get-ComputerDetails {

[CmdletBinding()]

param (

[parameter(Mandatory=$true,ValueFromPipeline=$true)]

[string[]]$computername

)

BEGIN {}

PROCESS {

. Вы заметите, что главное различие между расширенной функцией и фильтром заключается в наличии дополнительных атрибутов, таких как [CmdletBinding()], [parameter] и так далее. В данном примере параметр $computername был создан для приема одной или нескольких строк в качестве входных данных из конвейера, и является обязательным. При использовании этой технологии переменная $_ внутри блока PROCESS не является обязательной. Вместо нее входные данные могут помещаться в параметр $computername. Скриптовый блок PROCESS помещает один входящий объект в параметр $computername за один раз и выполняется один раз для каждого объекта.

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

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


Список литературы


  1. Lee Holmes. Windows PowerShell Cookbook: The Complete Guide to Scripting Microsoft's New Command Shell, O’Reilly, 2010, ISBN-10: 0596801505,ISBN-13: 978-0596801502

  2. Ed Wilson. Windows PowerShell 2.0 Best Practices, Best Practices (Microsoft), 2010, ISBN-10: 0735626464, ISBN-13: 978-0735626461

  3. Попов А., Введение в Windows PowerShell, БХВ-Петербург,2009, ISBN5-9775-0283-4

  4. MS Official course 10325A Automating Administration with Windows PowerShell® 2.0, Microsoft, 2010



Поделитесь с Вашими друзьями:
1   ...   19   20   21   22   23   24   25   26   27


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал