Неожиданные результаты в Receive-Job

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

Бег

Start-Job { New-Object PSObject -Property @{ A = 1 } } |
  Receive-Job -Wait -AutoRemoveJob

возвращается

A                     : 1
RunspaceId            : 6921e85f-301e-4e95-8e4b-c0882fc2085f
PSSourceJobInstanceId : 2992ef77-5642-4eac-8617-f26449a87801

Бег

Start-Job { New-Object PSObject } | Receive-Job -Wait -AutoRemoveJob

возвращается

@{PSComputerName=localhost; RunspaceId=3e783d5f-254a-4951-bb4a-7ff6fa2812c5; PSShowComputerName=False; PSSourceJobInstanceId=1d951dec-0823-4cde-8219-4a6263550441}

Тем не менее, бег

Start-Job { ,@(New-Object PSObject -Property @{ A = 1 }) } |
  Receive-Job -Wait -AutoRemoveJob

возвращается

A
-
1

Почему командлет Receive-Job добавляет эту хэш-таблицу только для PSObjects?

ОБНОВЛЕНИЕ: то же самое в PowerShell 4.0.


person ernestasju    schedule 21.10.2016    source источник
comment
FWIW, он ведет себя так же для PSCustomObject: Start-Job { [PSCustomObject]@{A=1} } | Receive-Job -Wait -AutoRemoveJob   -  person Charlie Joynt    schedule 21.10.2016
comment
@PetSerAl, я не знал, что он также добавляет свойства примечаний к целым числам и строкам. Не могли бы вы написать это как ответ?   -  person ernestasju    schedule 24.10.2016
comment
@PetSerAl: Отличные указатели, спасибо. Однако я не думаю, что вызывается .ToString() (по крайней мере, не непосредственно для объекта), и есть 3 набора из 3-5 свойств, связанных с удаленным взаимодействием, которые запускают это форматирование (если они являются единственными свойствами). Я разместил свои выводы в качестве ответа - пожалуйста, дайте мне знать, если я что-то не так.   -  person mklement0    schedule 26.10.2016
comment
@PetSerAl: понял, еще раз спасибо; .PSObject часть .PSObject.ToString() была недостающей частью головоломки - ответ обновлен. (Если есть что добавить/исправить, пишите в комментарии здесь).   -  person mklement0    schedule 26.10.2016
comment
Если ответ решает вашу проблему, примите его, нажав большую галочку (✓) рядом с ним, и, при желании, также проголосуйте за него (для этого требуется не менее 15 очков репутации). Если вы нашли другие ответы полезными, пожалуйста, проголосуйте за них. Принятие и голосование помогает будущим читателям. См. соответствующую статью справочного центра. Если на ваш вопрос еще нет полного ответа, оставьте отзыв. Если вы считаете, что нашли лучшее решение самостоятельно, опубликуйте его как ответ и примите себя.   -  person mklement0    schedule 11.11.2016


Ответы (2)


PowerShell не является оболочкой WYSIWYG. Обычно «то, что вы получаете» — это не текст, а объекты со свойствами и методами. А «то, что вы видите» — это их некое текстовое представление. Во многих случаях по умолчанию PowerShell отображает не все свойства объекта, а только наиболее распространенные, как определено в файлах форматирования. И некоторые объекты используют пользовательское форматирование, например, строки и целые числа отображают только свое значение, но не какие-либо свойства, а коллекции отображают свое содержимое, но не сами коллекции.

Так что, по сути, PowerShell добавляет дополнительные свойства ко всем объектам, полученным от задания. Но эти свойства не всегда отображаются. Вы можете увидеть эти дополнительные свойства, передав выходные данные задания командлету Get-Member:

Start-Job { 1,'',@() } | Receive-Job -Wait -AutoRemoveJob | Get-Member

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

Start-Job { 1,'',@() } | Receive-Job -Wait -AutoRemoveJob | Format-List -Force -Expand CoreOnly
person user4003407    schedule 25.10.2016

Чтобы дополнить прекрасный ответ PetSerAl уделить внимание хеш-таблице, которая была 't (хеш-таблица), основанная на полезных комментариях PetSerAl:

Выход из Start-Job { New-Object PSObject } | Receive-Job -Wait -AutoRemoveJob,

@{PSComputerName=localhost; RunspaceId=3e783d5f-254a-4951-bb4a-7ff6fa2812c5; PSShowComputerName=False; PSSourceJobInstanceId=1d951dec-0823-4cde-8219-4a6263550441}

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

Это представление подозрительно похоже на литерал хеш-таблицы, но кавычки вокруг значений, которые обычно необходимы, отсутствуют, например, вокруг localhost.
Также обратите внимание, что вывод фактического хеш-таблица дает гораздо более удобный формат "ключ-значение" с двумя столбцами.

Обратите внимание, что PS по-прежнему считает пользовательский объект, который изначально не имел свойств, лишенным свойств, даже после того, как сама PS добавила к нему свойства, например, с помощью Receive-Job здесь — подробности см. ниже.

В своем исходном состоянии (PS еще не добавила никаких свойств) объект без свойств выводит по умолчанию пусто (пустая строка). (Попробуйте New-Object PSCustomObject непосредственно в командной строке. )

После того как Receive-Job добавит свои "мета" свойства в пользовательский объект, их существование активирует форматирование выходных данных, подобное хэш-таблице.


PetSerAl предоставил ссылку на исходный код, из которого следует, что форматирование "PropertyLessObject" срабатывает при следующих условиях:

  • Объект вообще не имеет свойств или имеет только свойства, автоматически добавленные PowerShell в контексте remoting (которое, по-видимому, также включает командлеты, связанные с job), как это сделано Receive-Object здесь .

  • Иными словами: свойства, автоматически добавляемые PS, не учитываются при принятии решения о том, является ли объект бессвойственным.

Ссылка на исходный код сообщит вам конкретные наборы свойств удаленного взаимодействия из 3, 4 или 5 элементов, которые можно добавить во время удаленного взаимодействия и активировать форматирование, но вот минимальный пример (с 3 свойствами).
Снова , обратите внимание, что форматирование, подобное хеш-таблице, запускается только потому, что единственные свойства, которые есть у объекта, названы в соответствии с автоматически добавляемыми свойствами, связанными с удаленным взаимодействием:

PS> [PSCustomObject] @{PSComputerName='Hi, Mom'; RunspaceId=0; PSShowComputerName=$true}
@{PSComputerName=Hi, Mom; RunspaceId=0; PSShowComputerName=False}

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

Вы можете форсировать обычное представление списка или таблицы с помощью Format-List -Force или Format-Table -Force, но обратите внимание, что логическое свойство PSShowComputerName никогда не отображается, а вместо этого неявно контролирует, связанный > PSComputerName свойство включено в список/таблицу.


PetSerAl также отмечает, что вы можете получить формат вывода, подобный хеш-таблице, по запросу для любого настраиваемого объекта: просто вызовите .PSObject.ToString() (обратите внимание на ключевую часть .PSObject; без нее вы получите пустой вывод).

PS> ([pscustomobject] @{ one = 'Hi, Mom'; two = 2 }).PSObject.ToString()
@{one=Hi, Mom; two=2}

Или, проще говоря, с интерполяцией строк (которая, предположительно, просто вызывает .PSObject.ToString() за кулисами):

PS> "$([pscustomobject] @{ one = 'Hi, Mom'; two = 2 })"
@{one=Hi, Mom; two=2}

Обратите внимание, что эта интерполяция строк не работает для экземпляров любых других типов (объекты не типа [System.Management.Automation.PSCustomObject]):

  • PowerShell использует свой метод .ToString(), даже когда вы вызываете .PSObject.ToString().

  • Непосредственно основанный на .NET тип (например, добавленный с помощью Add-Type) по умолчанию просто возвращает свое полное имя типа (как из .ToString() / .PSObject.ToString(), так и в качестве вывода по умолчанию в PS); например.:

    PS> (Add-Type -PassThru 'namespace net.same2u { public class SomeType {} }')::New()
    net.same2u.SomeType  # the full type name
    
  • То же самое относится к экземплярам пользовательских классов PowerShell (определяемых с помощью class { ... }).

person mklement0    schedule 26.10.2016