Write-Output -InputObject (,'Test') -NoEnumerate

Я думаю, что это ошибка, которая относится только к PowerShell Windows 5.1:

Переключатель -NoEnumerate не работает, когда ввод осуществляется через именованный аргумент -InputObject:

Следующая функция возвращает False:

Function Test {Write-Output -InputObject (,'Foo') -NoEnumerate} 
(Test) -is [Array]

Пока эта функция возвращает True:

Function Test {Write-Output (,'Foo') -NoEnumerate} 
(Test) -is [Array]

PowerShell Windows

Name                           Value
----                           -----
PSVersion                      5.1.17134.858
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17134.858
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Проблема не отображается в PowerShell Core.
(обе функции возвращают True)

Name                           Value
----                           -----
PSVersion                      6.2.0-preview.1
PSEdition                      Core
GitCommitId                    6.2.0-preview.1
OS                             Microsoft Windows 10.0.17134
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Хотя в описании Write-Output командлет, относящийся к переключателю -NoEnumeration:

Примечание

Этот переключатель корректно работает только с PowerShell Core 6.2 и новее. В более старых версиях PowerShell Core коллекция по-прежнему перечисляется даже при использовании этого переключателя. Поведение в PowerShell Core 6.2 соответствует Windows PowerShell.

(Если я правильно понял, я понимаю, что переключатель -NoEnumeration должен работать только для PowerShell Windows)

Я сообщил о проблеме здесь в Windows PowerShell [UserVoice] в соответствии с инструкциями здесь от Сообщество PowerShell GitHub, но это похоже на черную дыру... (Я уже сообщал о проблемах, но почти не видел ответа).

Вопросы:
Это действительно ошибка или я что-то упустил?
Если это ошибка, то Windows PowerShell [UserVoice] по-прежнему является правильным адресом для сообщения о такой проблеме?


person iRon    schedule 11.07.2019    source источник
comment
Да, это известный баг. Нет, вы не можете это исправить. Это было недавно исправлено в версии 6.2.   -  person Maximilian Burszley    schedule 11.07.2019
comment
github.com/PowerShell/PowerShell/issues/5955   -  person Maximilian Burszley    schedule 11.07.2019
comment
@TheIncorrigible1, спасибо за ответ. Я столкнулся с этой проблемой, но не смог связать ее с тем, как она мне представлялась: с использованием (или без использования) именованного параметра -InputObject).   -  person iRon    schedule 11.07.2019
comment
Документы, указанные в вашем вопросе, действительно неверны на момент написания этой статьи. Их исправление было запрошено в этой проблеме GitHub.   -  person mklement0    schedule 30.01.2020


Ответы (1)


Действительно, ошибка в Windows PowerShell (до версии 5.1, последней выпущенной версии — поскольку ошибка не является критической с точки зрения безопасности, маловероятно будет исправлено) по-прежнему вызывает перечисление при передаче -NoEnumerate, хотя и только на один уровень.[1]

Эта ошибка была исправлена ​​в PowerShell [Core] начиная с (по крайней мере) версии 6.2.3[2].

Чтобы продемонстрировать проблему (все приведенные ниже команды теперь работают должным образом в PowerShell [Core]):

WinPS> (Write-Output -NoEnumerate -InputObject 1, 2 | Measure-Object).Count
2 # !! Should be *1*, because a *single array* (with 2 elements) was passed.

Примечание. Заманчиво опустить Measure-Object в приведенной выше команде, но это приведет к искажению результатов: при использовании () оператор группировки вокруг команды в контексте выражения приводит к тому, что вывод этой команды перечислено.

Существует обходной путь: опустить -InputObject, т. е. передать коллекцию в качестве позиционного аргумента, что неожиданно приводит к тому, что аргумент передается как есть (тогда как явное использование -InputObject перечисляет аргумент во время привязки параметра):

# POSITIONAL argument binding, without -InputObject
WinPS> (Write-Output -NoEnumerate 1, 2 | Measure-Object).Count
1 # OK

Обратите внимание, что этот обходной путь не работает с конвейерным вводом, хотя это необычный сценарий, учитывая, что большинство команд не< /em> выводить коллекции в целом в конвейер (они отправляют свои элементы, один за другим):

WinPS> ( , (1, 2) | Write-Output -NoEnumerate | Measure-Object ).Count
2 # !! Should be *1*: the unwrapped outer array contains a *single [array]* element

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

Таким образом, этот метод одноэлементного массива-оболочки представляет собой краткую и более быструю альтернативу самому Write-Output -NoEnumerate, поэтому, по сути, , (1, 2) сам по себе является конвейерным обходной путь: он записывает операнд массива (1, 2) в целом в выходной поток (успешно).


[1] Неиспользование -NoEnumerate дополнительно демонстрирует связанную ошибку в Windows PowerShell: слишком много перечисления происходит, когда -InputObject используется явно:

Ошибочно применяется один уровень рекурсии: элементы входной коллекции неожиданно также перечисляются (опять же, PowerShell [Core] теперь работает правильно):

WinPS> (Write-Output -InputObject 1, (2, 3) | Measure-Object).Count
3 # !! This should be *2*, because the single input array has only 2 elements.
  # !! That the 2nd element is itself an array should not matter.

Опять же, обходной путь состоит в том, чтобы опустить -InputObject:

# POSITIONAL argument binding, without -InputObject
WinPS> (Write-Output 1, (2, 3) | Measure-Object).Count
2 # OK

[2] Однако, начиная с PowerShell [Core] 7.0.0-rc.2, по-прежнему существует ошибка при объединении
-NoEnumerate с скалярным аргументом, который позиционно привязано
:

PSCore> (Write-Output -NoEnumerate 42).GetType().Name
List`1 #`# !! scalar 42 was unexpectedly wrapped in a *list*

Временное решение заключается в использовании -InputObject явно:

# OK thanks to -InputObject
PSCore> (Write-Output -NoEnumerate -InputObject 42).GetType().Name
Int32 # OK

Ошибка отслеживается в этой проблеме GitHub.

person mklement0    schedule 30.01.2020