Неожиданные результаты в 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= локальный; 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
возвращается
- 1
Почему Receive-Job
Командлет добавить, что хеш-таблица только для PSObject
s?
ОБНОВЛЕНИЕ: то же самое в PowerShell 4.0.
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
В дополнение к отличному ответу PetSerAl с акцентом на хеш-таблицу, которая не была (хеш-таблица), основываясь на полезных комментариях 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 в контексте удаленного взаимодействия (который, очевидно, также включает командлеты, связанные с заданием), как это делается
Receive-Object
Вот.Другими словами: свойства, автоматически добавленные PS, не учитываются при принятии решения, является ли объект не имеющим свойств.
Ссылка на исходный код расскажет вам о конкретных 3-, 4- или 5-элементных наборах свойств удаленного взаимодействия, которые могут быть добавлены во время удаленного взаимодействия и инициировать форматирование, но вот минимальный пример (3 свойства).
Опять же, обратите внимание, что форматирование, похожее на хеш-таблицу, запускается только потому, что единственные свойства объекта имеют имена для связанных с удаленным взаимодействием автоматически добавляемых свойств:
> [PSCustomObject] @{PSComputerName='Hi, Mom'; RunspaceId=0; PSShowComputerName=$false}
@{PSComputerName=Hi, Mom; RunspaceId=0; PSShowComputerName=False}
Обратите внимание, что хотя в команду включен хеш-литерал, он просто используется для создания пользовательского объекта.
Вы можете заставить обычный список или табличное представление с Format-List -Force
или же Format-Table -Force
Обратите внимание, что логическое свойство PSShowComputerName
никогда не появляется и вместо этого неявно контролирует, связан ли PSComputerName
свойство включено в список / таблицу.
PetSerAl также указывает, что вы можете получить формат вывода, похожий на хеш- таблицу, по требованию для любого пользовательского объекта: просто вызовите .PSObject.ToString()
(обратите внимание на решающее .PSObject
часть; без этого вы получите пустой вывод).
> ([pscustomobject] @{ one = 'Hi, Mom'; two = 2 }).PSObject.ToString()
@{one=Hi, Mom; two=2}
Или, проще, с интерполяцией строк (которая, по-видимому, просто вызывает .PSObject.ToString()
за кулисами):
> "$([pscustomobject] @{ one = 'Hi, Mom'; two = 2 })"
@{one=Hi, Mom; two=2}
Обратите внимание, что это не работает для экземпляров любых других типов (объекты, не производные от [System.Management.Automation.PSObject]
):
PowerShell полагается на их
.ToString()
метод, даже когда вы вызываете.PSObject.ToString()
,Тип, основанный непосредственно на.NET (например, как добавлено с
Add-Type
) по умолчанию просто возвращает полное имя типа (оба из.ToString()
/.PSObject.ToString()
и как вывод по умолчанию в PS); например:> (Add-Type -PassThru 'namespace net.same2u { public class SomeType {} }')::New() net.same2u.SomeType # the full type name