Главная страница

Эффективное программирование в Windows PowerShell Разбираться в Windows PowerShell и получать от него больше


Скачать 0.88 Mb.
НазваниеЭффективное программирование в Windows PowerShell Разбираться в Windows PowerShell и получать от него больше
АнкорEffective_Windows_Powershell_RU
Дата22.05.2020
Размер0.88 Mb.
Формат файлаpdf
Имя файлаEffective_Windows_Powershell_RU.pdf
ТипРеферат
#124663
страница4 из 6
1   2   3   4   5   6
25

Эксперименты показывают, что если объект содержит менее четырех свойств, PowerShell использует для его отображения таблицу. Если у объекта пять и более свойств, PowerShell выводит их в виде списка.
Возможно определить несколько видов отображения для одного типа .NET. Отображение определяется в
XML-файлах форматирования, расположенных в папке установки PowerShell:
PS> Get-ChildItem $PSHOME\*format*
Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows\System32\
WindowsPowerShell\v1.0
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 1/24/2007 11:23 PM 22120 Certificate.format.ps1xml
-a--- 1/24/2007 11:23 PM 60703 DotNetTypes.format.ps1xml
-a--- 1/24/2007 11:23 PM 19730 FileSystem.format.ps1xml
-a--- 1/24/2007 11:23 PM 250197 Help.format.ps1xml
-a--- 1/24/2007 11:23 PM 65283 PowerShellCore.format.ps1xml
-a--- 1/24/2007 11:23 PM 13394 PowerShellTrace.format.ps1xml
-a--- 1/24/2007 11:23 PM 13540 Registry.format.ps1xml
Содержание этих файлов выглядит следующим образом:

process

System.Diagnostics.Process
Deserialized.System.Diagnostics.Process





7
right



7
right



8
right



10
26

right



5
right



8
right


6
right







HandleCount


[int]($_.NPM / 1024)


[int]($_.PM / 1024)


[int]($_.WS / 1024)


[int]($_.VM / 1048576)



if ($_.CPU -ne $()) {
$_.CPU.ToString("N")
}



Id


ProcessName


27





Это XML-определение табличного отображения для типа Process. Оно определяет атрибуты отображаемых колонок, данных которые в них отображаются и в некоторых случаях производит преобразование данных к более удобному отображению (например, перевод байтов в Кб или Мб). А вот определение для того же типа в для отображения в виде столбцов (Format-Wide):

process

System.Diagnostics.Process





ProcessName





В этом типе отображения выводится лишь одно свойство - ProcessName. Поискав в
DotNetTypes.format.ps1xml, мы найдем больше определений. Например, именованное форматирование
StartTime не вызывается по умолчанию. Вы можете применить его, указав имя в командлете Format-
Table:

StartTime

System.Diagnostics.Process


$_.StartTime.ToShortDateString()





20


10
right


28

13
right


12
right






ProcessName


Id


HandleCount


WorkingSet






Зачем я всё это показываю вам? Я думаю, важно понять то "волшебство", благодаря которому объекты
.NET из двоичных сущностей превращаются в текст, отображаемый в вашей консоли. Обладая этими знаниями, вы никогда не должны забывать о том, что вы имеете дело в первую очередь с объектами
.NET.
Существует ли простой способ выяснить, какие выводы отображения доступны для того или иного типа .NET? Да, если у вас установлены расширения PowerShell Community Extensions. PSCX предлагает удобный сценарий, написанный Joris van Lier, который называется Get-ViewDefinition и его можно использовать вот так:
PS> Get-Viewdefinition System.Diagnostics.Process
Name : process
Path : C:\Windows\System32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml
TypeName : System.Diagnostics.Process
SelectedBy : {System.Diagnostics.Process, Deserialized.System.Diagnostics.Process}
GroupBy :
Style : Table
Name : Priority
Path : C:\Windows\System32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml
TypeName : System.Diagnostics.Process
29

SelectedBy : System.Diagnostics.Process
GroupBy : PriorityClass
Style : Table
Name : StartTime
Path : C:\Windows\System32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml
TypeName : System.Diagnostics.Process
SelectedBy : System.Diagnostics.Process
GroupBy :
Style : Table
Name : process
Path : C:\Windows\System32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml
TypeName : System.Diagnostics.Process
SelectedBy : System.Diagnostics.Process
GroupBy :
Style : Wide
Эти данные могут показать все доступные формы отображения. Возможно, о каких-то вы не были осведомлены. Давайте проверим эти дополнительные формы:
PS> Get-Process | Format-Wide
AcroRd32 ADCDLicSvc alg ati2evxx ati2evxx BTNtService ccApp CCC
ccEvtMgr ccSetMgr csrss ctfmon
DefWatch editplus explorer GoogleUpdate
Idle lsass mdm mDNSResponder miranda32 MOM
opera PnkBstrA
powershell RTHDCPL
Rtvscan scsiaccess
PS> Get-Process | Format-Table -View Priority
PriorityClass: Normal
ProcessName Id HandleCount WorkingSet
----------- -- ----------- ----------
AcroRd32 3388 239 59809792
ADCDLicSvc 496 36 1212416
alg 2440 107 3584000
30
csrss 764 667 5844992
ctfmon 2732 80 3575808
DefWatch 580 55 5087232
editplus 2508 85 7794688
explorer 1716 690 17539072
PriorityClass: High
ProcessName Id HandleCount WorkingSet
----------- -- ----------- ---------- winlogon 800 465 4407296
PS> Get-Process | Format-Table -View StartTime
StartTime.ToShortDateString(): 21.03.2009
ProcessName Id HandleCount WorkingSet
----------- -- ----------- ----------
AcroRd32 3388 239 60645376
ADCDLicSvc 496 36 1212416
alg 2440 107 3584000
ati2evxx 1036 88 3440640
ati2evxx 1292 107 3805184
BTNtService 528 82 2449408
ccApp 2700 285 7659520
StartTime.ToShortDateString(): 01.01.1601
ProcessName Id HandleCount WorkingSet
----------- -- ----------- ----------
System 4 744 262144
StartTime.ToShortDateString(): 21.03.2009
ProcessName Id HandleCount WorkingSet
----------- -- ----------- ---------- winlogon 800 465 4407296
Что делать, если вы забыли, какие способы форматирования доступны? Главное - не забыть, что вы можете использовать Get-Command:
31

PS> Get-Command Format-*
CommandType Name Definition
----------- ---- ----------
Cmdlet Format-Custom Format-Custom [[-Property] ] [-Depth <...
Cmdlet Format-List Format-List [[-Property] ] [-GroupBy <...
Cmdlet Format-Table Format-Table [[-Property] ] [-AutoSize...
Cmdlet Format-Wide Format-Wide [[-Property] ] [-AutoSize] [...
Вы уже знакомы с Format-Table. Он отображает данные в формате таблицы. Этот формат используется по умолчанию для многих объектов, включая System.Diagnostics.Process. Format-Wide также довольно понятен. PowerShell выводит одно свойство (как правило, наиболее информативное) в несколько колонок. Format-Custom интересен, но вряд ли вы будете им часто пользоваться - он будет вызываться для типов .NET, имеющих пользовательский формат, наподобие System.DateTime:

DateTime

System.DateTime






DateTime






DateTime имеет тип ScriptProperty, который PowerShell определяет так:
PS> Get-Date | Get-Member -Name DateTime
TypeName: System.DateTime
Name MemberType Definition
---- ---------- ----------
DateTime ScriptProperty System.Object DateTime {get=if ($this.DisplayHint -i
Так мы подходим к моему любимому методу форматирования для исследования вывода PowerShell. Вы наверняка заметили, что содержание колонки Definition обрезается. Если необходимо вывести её полное содержание, используйте командлет Format-List. Этот командлет выводит различные значения свойств в отдельных строках, так что данные редко сокращаются. Например:
32

PS> Get-Date | Get-Member -Name DateTime | Format-List
TypeName : System.DateTime
Name : DateTime
MemberType : ScriptProperty
Definition : System.Object DateTime {get=if ($this.DisplayHint -ieq "Date")
{
"{0}" -f $this.ToLongDateString()
}
elseif ($this.DisplayHint -ieq "Time")
{
"{0}" -f $this.ToLongTimeString()
}
else
{
"{0} {1}" -f $this.ToLongDateString(),
$this.ToLongTimeString()
};}
Теперь мы видим полное определение свойств DateTime. Замечание: часто PowerShell выводит сокращённый набор значений свойств с помощью командлета Format-List. Это делается для того, чтобы отсекать обычно ненужную информацию. Однако, если вам необходим самый подробный вывод всех деталей, используйте этот командлет так: "format-list *".
Смотрите, вот стандартный вывод для объекта Process:
PS> (Get-Process)[0] | Format-List
Id : 3388
Handles : 230
CPU : 33,328125
Name : AcroRd32
А здесь мы запрашиваем вывод всех свойств:
PS> (Get-Process)[0] | Format-List *
__NounName : Process
Name : AcroRd32
Handles : 230
VM : 186585088
WS : 73781248
PM : 71942144
NPM : 8760
Path : C:\Program Files\Adobe\AcroRd32.exe
Company : Adobe Systems Incorporated
CPU : 33,59375
FileVersion : 8.1.0.2007051100
ProductVersion : 8.1.0.2007051100
Description : Adobe Reader 8.1
33

Product : Adobe Reader
Id : 3388
Понимаете, о чём я? Посмотрите, как много информации может быть не выведено, если вы символом звёздочки не укажете, что хотите видеть все свойства объекта.
34

Часть 7: Режимы синтаксического разбора PowerShell
Способ, которым PowerShell осуществляет разбор строк, может удивить тех, кто ранее использовал оболочки с упрощенным парсингом, такие как CMD.EXE. Парсинг в PowerShell значительно отличается, так как он используется и как интерактивная оболочка командной строки, и как язык сценариев.
Сложность заключалась в том, что разработчикам необходимо было:
1. Позволить выполнение команд и программ с аргументами в командной строке. Следствие: аргументы (имена файлов, пути) не должны требовать кавычек, если в аргументе отсутствуют пробелы.
2. Позволять выполнение сценариев, содержащих выражения, которые аналогичны выражениям в большинстве языков скриптов/программирования. Следствие: Сценарий PowerShell должен верно определять выражения вида 2 + 2 и $date.Second, а также строки, использующие кавычки типа "del -r * is being executed".
3. Предоставить возможность копирования интерактивно введенного кода и вставки его в сценарий для последующего применения. Следствие: эти две области применения - интерактивная и скриптовая - должны "уживаться".
Частью мощного языка сценариев должна являться поддержка не только данных строкового типа.
Фактически PowerShell поддерживает большинство типов .NET, включая String, Int8, Int16, Int32, Decimal,
Single, Double, Boolean, Array, ArrayList, StringBuilder и многие другие .NET-типы. Звучит неплохо, но всё же
- что там с режимами разбора? Давайте подумаем, как язык может представлять строчный литерал? Ну, большинство, как правило, ожидают эту строку: "Hello World". Фактически, PowerShell распознаёт её как строку:
PS> "Hello World".GetType().Name
String
PS> "Hello World"
Hello World
Если вы напечатаете строку сразу за приглашением и нажмёте клавишу Enter, PowerShell, благодаря среде REPL(Read-eval-print-loop), отобразит её в консоли, как показано выше. А если необходимо указать аргумент для команды в кавычках?
PS> del "foo.txt", "bar.txt", "baz.txt"
Вы сразу ощутите отличия от других оболочек. Хуже того, эти кавычки довольно быстро начинают надоедать. Я думаю, что разработчики PowerShell вовремя решили, что им понадобятся два различных режима синтаксического анализа строк. Во-первых, необходимо разбирать строки так, как это делают традиционные оболочки, в которых имена файлов и процессов, путей не обрамляются кавычками. Во- вторых, необходимо иметь возможность воспринимать строковое выражение так, как это принято в языках программирования - заключая его в кавычки. В PowerShell первый режим называется режим разбора команд, а второй - режим разбора выражений. Важно понимать, в каком режиме вы находитесь в данный момент, и ещё важней - как переключаться между ними.
Давайте взглянем на пример. Очевидно, хотим ввести команду для удаления этих файлов:
PS> del foo.txt, bar.txt, baz.txt
Так даже лучше - для имён файлов кавычки не требуются. PowerShell обрабатывает эти имена как строковые выражения даже без кавычек в режиме команд. А что случится, если путь будет содержать пробелы? Вы можете сами попробовать это:
35

PS> del 'C:\Documents and Settings\Keith\_lesshst'
И это работает так, как и ожидалось. А если необходимо выполнить программу с пробелами в пути?
PS> 'C:\Program Files\Windows NT\Accessories\wordpad.exe'
C:\Program Files\Windows NT\Accessories\wordpad.exe
Такая конструкция не работает. PowerShell решил, что мы ввели строку и он просто отобразил её на экране. Это произошло потому, что PowerShell находится в режиме выражений. Нам необходимо сообщить ему, что эту строку необходимо анализировать в режиме команд. Для этого используется оператор '&':
PS> & 'C:\Program Files\Windows NT\Accessories\wordpad.exe'
Подсказка: для автоматического завершения части пути используйте Tab и Shift-Tab.
Если путь содержит пробелы, PowerShell также вставит оператор вызова и
автоматически поставит кавычки вокруг пути.
Этот пример показывает, что PowerShell анализирует первый не пустой символ в строке для определения, в каком режиме строка будет обработана. Любой из нижеприведённых символов переводит PowerShell в режим команд:
[_aA-zZ]
&
\
У этого правила есть одно исключение - если строка начинается с ключевого слова (if, do, while, foreach и т. д.), PowerShell переходит в режим выражений и будет ожидать оставшуюся часть выражения, связанную с этим ключевым словом.
Преимущества командного режима:

Строка не нуждается в обрамлении кавычками, если она не содержит пробелы

Числа обрабатываются как числа, все другие аргументы - как строки, за исключением тех, которые начинаются с @, $, (, ' или ". Числа интерпретируются как Int32, Int64, Double или Decimal
в зависимости от их написания и величины, необходимой для хранения числа, например, 12,
30GB, 1E-3, 100.01d.
Хорошо, а для чего нужен режим выражений? Ну, как я уже говорил, необходимо иметь возможность оценки выражений, таких, как это:
PS> 64-2 62
Не удивительно, что некоторые оболочки могут интерпретировать это выражение, например, попытавшись выполнить команду с именем '64-2'. Как же PowerShell определяет, что строку необходимо анализировать в режиме выражений? Если строка начинается с цифры, или одного из этих знаков - @, $,
(, ' или " - строка разбирается в режиме выражений. Преимущества этого режима:
36


Устранение возможности неверного толкования команд как строк, например, del -recurse * - это команда, а "del -recurse *" - это строка.

Прямое указание арифметических операций и сопоставления выражений, например 64-2 (62) и
$array.count -gt 100. В режиме команд -gt интерпретировалось бы как параметр, если предыдущая лексема соответствует верной команде.
Одним из следствий правил режима анализа строк является то, что для запуска исполняемых файлов или сценариев с именами, начинающимися с цифры, необходимо заключать их в кавычки и использовать оператор вызова:
PS> & '64E1'
Если вы попытаетесь выполнить 64E1 без оператора вызова, PowerShell не сможет понять, хотите вы ввести число 64E1(640) или выполнить исполняемый файл с именем 64E1.exe или 64E1.ps1. В этом случае зависит от вас, в какой режим анализа перейдет PowerShell.
Примечание: я заметил, что в случае указания полного имени (например, 64E1.ps1 или
64E1.exe), нет необходимости заключать команду в кавычки.
А что делать, если в одной строке необходимо сочетать различные режимы? Легко. Просто используйте выражения группировки (), подвыражение $() или подвыражение массива @(). Это заставит парсер производить повторную оценку режима синтаксического анализа, который будет произведён по первому символу внутри скобок.
Чем различаются выражения группировки (), подвыражения $() и подвыражения массива @()?
Выражение группировки может содержать лишь простое выражение или простой конвейер.
Подвыражение может содержать несколько операторов, разделённых точкой с запятой. Вывод каждого оператора передаётся на вывод подвыражения, который может быть скаляром, коллекцией или пустым множеством. Массив подвыражений ведет себя точно так же, как подвыражение, за исключением того, что он гарантирует, что выводом будет массив. Два случая, имеющих различия:
1. Когда массив не имеет вывода, подвыражение вернёт пустой массив
2. Если результатом является скалярное значение, будет выведен массив с одним элементом, содержащим скалярную величину.
Если выводом уже является массив, то использование оператора массива не действует, то есть массив не будет ещё раз "обёрнут" в другой массив.
В следующем примере я внедрю команду "Get-ChildItem C:\Windows" в строку, разбор которой начинается в режиме выражений. Когда будет встречено выражение группировки (get-childitem
c:\windows), начнётся новая оценка режима анализа. Обнаружив, что первым символом является 'g', парсер перейдёт в режим команд до конца текста внутри выражения группировки. Замечу, что ".Lehgth" анализируется в режиме выражений, поскольку не входит в выражение группировки, и PowerShell вернется обратно к предыдущему режиму парсинга. ".Lehgth" заставляет PowerShell получить свойство
Lehgth для объекта, выведенного выражением группировки. В моём случае, это массив объектов FileInfo
и DirectoryInfo. Свойство Lehgth сообщит количество элементов в этом массиве.
PS> 10 + (get-childitem c:\windows).Length
115
Мы можем сделать наоборот. То есть, вставить выражение в строку, разбор которой начинается в командном режиме. В примере ниже мы используем выражение, вычисляющее количество объектов, выбранных из последовательности.
1   2   3   4   5   6


написать администратору сайта