Ошибка PowerShell? не может передать свойство computername в get-service

Похоже, ошибка, нет? В этом случае powershell преобразует хеш-таблицу в строку '@{computername=comp001}' и пытается использовать ее с -Name (ByValue) вместо -ComputerName (ByPropertyName). Даже PS 6 делает это. Трубопровод "get-service -name *" работает нормально.

PS C:\> [pscustomobject]@{computername='comp001'} | get-service
get-service : Cannot find any service with service name '@{computername=comp001}'.
At line:1 char:45
+ [pscustomobject]@{computername='comp001'} | get-service
+                                             ~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (@{computername=comp001}:String) 
[Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : 
NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

2 ответа

Похоже, ошибка, нет?

Не ошибка как таковая, но неожиданное следствие разработки параметров Get-Service командлет:

Пометить типизированный параметр [string] / [string[]] или же [object] / [object[]] (или же [psobject] / [psobject[]] ) с ValueFromPipeline Атрибут делает этот параметр привязанным к любому входу конвейера, возможно, в дополнение к привязке к другим параметрам - если только этот параметр не связан аргументом командной строки, который является вашим
-Name * обходной путь делает.

  • Причина в том, что экземпляры любого типа данных могут быть преобразованы в [string] / получены из [object] ([psobject]), вызывая привязку всех входных объектов, независимо от типа, к этому параметру.

Короче говоря, проблема здесь не в том [pscustomobject]@{computername='comp001'} не связан с
-ComputerName - это на самом деле - это то, что это также связано с -Name неизменно.
Механизм связывания параметров PowerShell фундаментально связывает входные данные конвейера со всеми подходящими параметрами, а не только с одним.

Как уже говорилось, единственный способ предотвратить -Name привязка из конвейера заключается в передаче значения по аргументу - даже если это значение просто * сигнализировать о включении услуг любого имени.

Поведение теперь также обсуждается на GitHub.


Примечание:

Как указывает js2010 (OP), возможно осмысленно объединить ValueFromPipeline а также ValueFromPipelineByPropertyName атрибуты в одном параметре так, что Get-Service "s -Name параметр делает, но обратите внимание на ограничения:

  • Работает только для не типизированного параметра [object] или же [psobject] / [object[]] или же [psobject[]] (такой параметр неизменно связывал бы все по значению, даже не учитывая свойства).

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

  • Пример команды, которая привязывает тот же сервис к -Name сначала как строка, а затем как объект с .Name имущество:
    'rpcss', [pscustomobject] @{ Name = 'rpcss' } | Get-Service

Как вы отправляете полный объект Get-ServiceУ него есть только два варианта привязки: Name а также InputObject, которые являются параметрами, которые принимают ByValue трубопроводный ввод. К сожалению, ваш объект не в той форме, которая либо понимает.

Вы можете увидеть, что делает PowerShell, запустив этот Trace-Command:

Trace-Command -Name ParameterBinding -PSHost -Expression {[pscustomobject]@{ComputerName='comp001'} | Get-Service}

Как вы говорите, способ обойти это заключается в предоставлении значения для -Nameпоэтому он не пытается связать это:

[pscustomobject]@{ComputerName='comp001'} | Get-Service -Name *

Еще раз, вы можете использовать Trace-Command как указано выше, чтобы увидеть, что теперь он счастлив связать '*' с -Nameзатем он связывает дополнительные параметры, такие как -ComputerName,

Документация PowerShell ( about_Parameters) гласит:

Если для параметра установлено значение "True (по значению)", Windows PowerShell пытается связать любые переданные по конвейеру значения с этим параметром, прежде чем он попытается интерпретировать команду другими методами.

Другие вопросы по тегам