Свойство объектов, отображаемое командлетом Format-Wide

Командлет Format-Wide служит для отображения какого-либо одного свойства объектов, поступаемых к нему по конвейеру, либо указанных в качестве значения параметра -InputObject.

Например, так:

Get-Process | Format-Wide

или так:

Format-Wide -InputObject (Get-Process)

В обоих случаях мы увидим несколько колонок, составленных из значений свойств ProcessName объектов System.Diagnostics.Process.

.format.ps1xml

Так как мы не указали какое-либо конкретное свойство, то командлет Format-Wide поступил так, как и полагается форматирующему командлету и посмотрел в файл DotNetTypes.format.ps1xml, расположенный в C:\Windows\System32\WindowsPowerShell\v1.0 для того чтобы осведомиться, нет ли так каких либо уже определенных представлений (view) для объектов System.Diagnostics.Process. Там это представление было и оно же и указало, что при отсутствии заданного параметра -Property нужно выводить значения свойства ProcessName.

        <View>
            <Name>process</Name>
            <ViewSelectedBy>
                <TypeName>System.Diagnostics.Process</TypeName>
            </ViewSelectedBy>
            <WideControl>
                <WideEntries>
                    <WideEntry>
                        <WideItem>
                            <PropertyName>ProcessName</PropertyName>
                        </WideItem>
                    </WideEntry>
                </WideEntries>
            </WideControl>
        </View>

Мы также можем узнать о существовании представлений для данных определенного типа данных не забираясь в дебри xml. Для этого нам нужно указать параметр -View, но в качестве его значения задать что-то, что бы точно не пришло в голову разработчикам командлетов, когда они думали о том, как бы назвать определенное представление. Например, так:

Get-Process | Format-Wide -View Some_Not_Very_Common_View_Name

Результатом выполнения этой команды станет сообщение об ошибке, в котором нам пояснят, что представления Some_Not_Very_Common_View_Name не существует, но есть такое: process.

Format-Wide : The view name Some_Not_Very_Common_View_Name cannot be found. 
Specify one of the following Wide views and try again: process.

Что же это за представление, мы можем узнать, введя команду:

Get-FormatData -TypeName System.Diagnostics.Process

В ответ мы получим что-то вроде:

TypeNames                    FormatViewDefinition
---------                    --------------------
{System.Diagnostics.Process} {process, process}

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

Get-FormatData -TypeName System.Diagnostics.Process | Select-Object -ExpandProperty FormatViewDefinition

или так:

Get-FormatData -TypeName System.Diagnostics.Process | ForEach-Object FormatViewDefinition

Заменив ForEach-Object его алиасом %, мы получим еще более компактную запись:

Get-FormatData -TypeName System.Diagnostics.Process | % FormatViewDefinition

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

Name    Control
----    -------
process System.Management.Automation.TableControl
process System.Management.Automation.WideControl

Как мы видим, для объектов типа System.Diagnostics.Process существует два представления, а именно: табличное представление, которое будет использоваться по умолчанию командлетом Format-Table, и то, которое нас сейчас интересует — для командлета Format-Wide. Тот факт, что оба этих представления фигурируют под одним и тем же именем — process — в данном случае не представляет каких-либо неудобств, так как это представления разного типа, использующиеся разными командлетами.

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

Get-FormatData -TypeName System.Diagnostics.Process | % FormatViewDefinition | select -Last 1

Мы получим следующий результат:

Name    Control
----    -------
process System.Management.Automation.WideControl

Уже знакомым способом получим содержимое свойства Control:

Get-FormatData -TypeName System.Diagnostics.Process | % FormatViewDefinition | select -Last 1 | % Control

Мы увидим:

Alignment : 0
Entries   : {System.Management.Automation.WideControlEntryItem}
AutoSize  : False
Columns   : 0
GroupBy   :
OutOfBand : False

И что нас тут более всего интересует, так это значение свойства Entries:

Get-FormatData -TypeName System.Diagnostics.Process | % FormatViewDefinition | select -Last 1 | % Control | % Entries

И тут мы увидим следующее:

DisplayEntry          SelectedBy EntrySelectedBy                              FormatString
------------          ---------- ---------------                              ------------
property: ProcessName {}         System.Management.Automation.EntrySelectedBy

где в первом столбце указано искомое свойство:

property: ProcessName 

.types.ps1xml

В случае, если для определенного типа данных не указно представление, которое мог бы использовать форматирующий командлет в отсутствие заданого параметра -Property, он заглядывает еще в одно место — в файлы описания типов.

На этот раз давайте приглядимся IPv6-адресам, а точнее к типу Microsoft.DnsClient.Commands.DnsRecord_AAAA. Объект данного типа мы можем получить попытавшись разрешить какое-либо доменное имя в IPv6-адрес, например:

Resolve-DnsName google.com -Type AAAA

Мы получим что-то вроде:

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
google.com                                     AAAA   206   Answer     2a00:1450:4010:c08::8a

Теперь, если мы передадим результат выполнения Resolve-DnsName командлету Format-Wide без указания параметра -Property, мы получим:

Resolve-DnsName google.com -Type AAAA | Format-Wide
2a00:1450:4010:c06::8b

Почему именно свойство IP6Address?

Мы знаем, что в отсутствие заданного параметра -Property форматирующие командлеты смотрят, определено ли какое-либо представление для выводимого типа данных.

Get-FormatData -TypeName Microsoft.DnsClient.Commands.DnsRecord_AAAA
TypeNames                                     FormatViewDefinition
---------                                     --------------------
{Microsoft.DnsClient.Commands.DnsRecord_A}    {Microsoft.DnsClient.Commands.DnsRecord_A_AAAA, Microsoft.DnsClient.Commands.DnsRecord_A_AAAA}
{Microsoft.DnsClient.Commands.DnsRecord_AAAA} {Microsoft.DnsClient.Commands.DnsRecord_A_AAAA, Microsoft.DnsClient.Commands.DnsRecord_A_AAAA}

Отбираем второй объект — Microsoft.DnsClient.Commands.DnsRecord_AAAA — и раскрываем содержимое свойства FormatViewDefinition:

Get-FormatData -TypeName Microsoft.DnsClient.Commands.DnsRecord_AAAA | select -last 1 | % formatviewdefinition

Получаем:

Name                                          Control
----                                          -------
Microsoft.DnsClient.Commands.DnsRecord_A_AAAA System.Management.Automation.TableControl
Microsoft.DnsClient.Commands.DnsRecord_A_AAAA System.Management.Automation.ListControl

Как мы видим из результата выполнения команды, для типа данных Microsoft.DnsClient.Commands.DnsRecord_AAAA существуют представления только для табличного (TableControl) и списочного (ListControl) вида, а представление типа WideControl для командлета Format-Wide — отсутствует.

Теперь завайте заглянем в слудеющее место, где форматирующий командлет будет искать информацию о параметрах вывода объекта определенного типа. В нашем случае — это файл DnsCmdlets.Types.ps1xml, находящийся в каталоге C:\Windows\System32\WindowsPowerShell\v1.0\Modules\DnsClient.

Заглянув в него, мы можем найти что-то вроде:

  <Type>
    <Name>Microsoft.DnsClient.Commands.DnsRecord_AAAA</Name>
    <Members>
      <AliasProperty>
        <Name>Address</Name>
        <ReferencedMemberName>IP6Address</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>IPAddress</Name>
        <ReferencedMemberName>IP6Address</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>QueryType</Name>
        <ReferencedMemberName>Type</ReferencedMemberName>
      </AliasProperty>
      <MemberSet>
        <Name>PsStandardMembers</Name>
        <Members>
          <PropertySet>
            <Name>DefaultDisplayPropertySet</Name>
            <ReferencedProperties>
              <Name>Name</Name>
              <Name>QueryType</Name>
              <Name>TTL</Name>
              <Name>Section</Name>
              <Name>IP6Address</Name>
            </ReferencedProperties>
          </PropertySet>
          <NoteProperty>
            <Name>DefaultDisplayProperty</Name>
            <Value>IP6Address</Value>
          </NoteProperty>
          <PropertySet>
            <Name>DefaultKeyPropertySet</Name>
            <ReferencedProperties>
              <Name>IP6Address</Name>
            </ReferencedProperties>
          </PropertySet>
        </Members>
      </MemberSet>
    </Members>
  </Type>

Эта структура определяет дополнительные свойства типа Microsoft.DnsClient.Commands.DnsRecord_AAAA, а также некоторую другую информацию. Нас же в данный момент интересуют выделенные строки. Как мы видим, здесь в качестве DefaultDisplayProperty указан IP6Address, что вполне сходится с тем, что мы получаем в качестве вывода.

Стоит сказать, что это значение действительно только в том случае, если для выводимого типа данных не определено ни одного представления соответствующего типа форматирования (Table, List, Wide, Custom). В противном случае DefaultDisplayProperty (для Format-Wide), равно как и DefaultDisplayPropertySet (для Format-Table, Format-List и Format-Custom) будут игнорироваться и использоваться будет именно представление.

Format-Wide

Однако у командлета Format-Wide есть еще одна интересная особенность — это использование определенных свойств в случае, если не задано значение параметра -Property, не существует каких-либо представлений и не определено значение DefaultDisplayProperty.

Например:

Get-Service | Format-Wide

Результатом этой команды будет вывод значений свойств Name объектов System.ServiceProcess.ServiceController. Однако, введя команду:

Get-Service | Format-Wide -View abcdefghijklm

мы получим:

Format-Wide : The view name abcdefghijklm cannot be found.
There are no existing Wide views for System.ServiceProcess.ServiceController objects.

Текст ошибки, полученный в результате выполнения предыдущей команды, сообщает, что для типа System.ServiceProcess.ServiceController вообще не существует представлений, что могли бы использоваться командлетом Format-Wide.

Точно так же, следующая команда:

Get-Service | Get-Member -MemberType MemberSet -Force -Name PSStandardMembers

выведет что-то вроде:

   TypeName: System.ServiceProcess.ServiceController

Name              MemberType Definition
----              ---------- ----------
PSStandardMembers MemberSet  PSStandardMembers {DefaultDisplayPropertySet}

Правая часть последней строки говорит нам о том, что для объекта службы определено только значение DefaultDisplayPropertySet, что используется командлетами Format-Table, Format-List и Format-Custom. Значения DefaultDisplayProperty, используемого командлетом Format-Wide, не существует (равно как и DefaultKeyPropertySet).

Возвращаясь в примеру с записями DNS, для типа Microsoft.DnsClient.Commands.DnsRecord_AAAA:

Resolve-DnsName google.com -Type AAAA | Get-Member -MemberType MemberSet -Force -Name PSStandardMembers 

мы видим:

   TypeName: Microsoft.DnsClient.Commands.DnsRecord_AAAA

Name              MemberType Definition
----              ---------- ----------
PSStandardMembers MemberSet  PSStandardMembers {DefaultDisplayProperty, DefaultDisplayPropertySet, DefaultKeyPropertySet}

что для типа Microsoft.DnsClient.Commands.DnsRecord_AAAA определены как DefaultDisplayProperty, так и DefaultDisplayPropertySet и DefaultKeyPropertySet.

Так почему же для объекта службы командлет Format-Wide вывел свойство Name?

Получается так, что в отсутствие каких-либо указаний, что посредством параметра -Property, что через файлы .format.ps1xml или types.ps1xml, командет Format-Wide выбирает свойства Name или ID, а также свойства, имена которых заканчиваются на name или ID. Причем Name приоритетнее, чем ID, а при существовании и Name и чего_нибудь_Name, опять же выбирается Name, что мы и видели в примере со службами, где присутствует и Name, и DisplayName, но выводится именно Name.

Проще это проверить, создав свой объект, для которого точно не будет определено каких-либо представлений и расширений типов:

$hash1 = @{
Description = "This is first object's description";
SomeID = "First Object's SomeID";
Some_Other_Data = "This is Some Other Data"
}

$hash2 = @{
Description = "This is second object's description";
SomeID = "Second Object's SomeID";
Some_Other_Data = "This is Some Other Data"
}


$objects = @(New-Object -TypeName PSCustomObject -Property $hash1)
$objects += New-Object -TypeName PSCustomObject -Property $hash2

$objects | Format-Wide

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

После этого мы создаем новый объект типа PSCustomObject используя имена и значения нашей первой хэш-таблицы и сохраняем его в переменную $objects. Причем мы сразу же задаем переменную $objects в виде массива, что пригодится нам, когда мы будем добавлять в нее второй объект. Делаем мы это при помощи конструкции @().

Далее мы добавляем к массиву в переменной $objects второй объект и передаем ее содержимое командлету Format-Wide.

Что мы получим в итоге, это значение свойств SomeID:

First Object's SomeID                            Second Object's SomeID                          

Теперь давайте к описанию объектов добавим свойство DisplayName:

$hash1 = @{
Description = "This is first object's description";
SomeID = "First Object's SomeID";
Some_Other_Data = "This is Some Other Data";
DisplayName = "First Object's DisplayName"
}

$hash2 = @{
Description = "This is second object's description";
SomeID = "Second Object's SomeID";
Some_Other_Data = "This is Some Other Data";
DisplayName = "Second Object's DisplayName"
}

$objects = @(New-Object -TypeName PSCustomObject -Property $hash1)
$objects += New-Object -TypeName PSCustomObject -Property $hash2

$objects | Format-Wide

Теперь в качестве результатов выполнения командлета Format-Wide мы получим значения свойств DisplayName:

First Object's DisplayName                       Second Object's DisplayName 

Продолжая наши изыскания, добавим ID:

$hash1 = @{
Description = "This is first object's description";
SomeID = "First Object's SomeID";
Some_Other_Data = "This is Some Other Data";
DisplayName = "First Object's DisplayName";
ID = "First Object's ID"
}

$hash2 = @{
Description = "This is second object's description";
SomeID = "Second Object's SomeID";
Some_Other_Data = "This is Some Other Data";
DisplayName = "Second Object's DisplayName";
ID = "Second Object's ID"
}

$objects = @(New-Object -TypeName PSCustomObject -Property $hash1)
$objects += New-Object -TypeName PSCustomObject -Property $hash2

$objects | Format-Wide

В качестве результата видим значение свойства ID:

First Object's ID                                Second Object's ID 

Теперь добавим свойство Name:

$hash1 = @{
Description = "This is first object's description";
SomeID = "First Object's SomeID";
Some_Other_Data = "This is Some Other Data";
DisplayName = "First Object's DisplayName";
ID = "First Object's ID";
Name = "First Object"
}

$hash2 = @{
Description = "This is second object's description";
SomeID = "Second Object's SomeID";
Some_Other_Data = "This is Some Other Data";
DisplayName = "Second Object's DisplayName";
ID = "Second Object's ID";
Name = "Second Object"
}

$objects = @(New-Object -TypeName PSCustomObject -Property $hash1)
$objects += New-Object -TypeName PSCustomObject -Property $hash2

$objects | Format-Wide

И в качестве вывода получаем его значение:

First Object                                     Second Object 

Что, собственно, и ожидалось.


Страницы в социальных сетях:

Twitter: https://twitter.com/vsseth
Facebook: https://fb.com/inpowershell
VKontakte: https://vk.com/inpowershell


Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s