Skip to content

Write-Output -NoEnumerate wrap singular items into PSObject[] #5122

Closed

Description

@PetSerAl

As far as I understand, issue caused by #2038.

Steps to reproduce

(Write-Output -NoEnumerate 1).GetType().FullName
(1 | Write-Output -NoEnumerate).GetType().FullName

Expected behavior

System.Int32
System.Int32

Actual behavior

System.Management.Automation.PSObject[]
System.Management.Automation.PSObject[]

Environment data

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.0.0-beta.8
PSEdition                      Core
GitCommitId                    v6.0.0-beta.8-46-ge3397b63e756bf432bbe80f5e9c4407d52d6b5b9
OS                             Microsoft Windows 10.0.15063
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Activity

  1. markekraus commented on Oct 15, 2017

    @markekraus
    Contributor

    Whoops.. meant to cancel my comment, not close the issue. I'm not sure if this is a bug or by design, but I'll label it as a bug until someone says otherwise.

  2. added a commit that references this issue on Nov 26, 2017
    673117c
  3. BrucePay commented on Mar 6, 2018

    @BrucePay
    Collaborator

    Hi PetSerAl PetSerAl,

    Actually this is by design from all the way back in v1.0. For consistency reasons, the team at that time decided that cmdlets would always return PSObjects. The PowerShell engine invocation APIs also always return collections of PSObject.

  4. PetSerAl commented on Mar 6, 2018

    @PetSerAl
    ContributorAuthor

    Bruce Payette (@BrucePay) As far as I understand PSObject and PSObject[] are different things. And that change in behavior of Write-Object was introduced quite recently. In v1.0 – v5.1 Write-Object does not behave that way.

  5. jzabroski commented on Jun 28, 2019

    @jzabroski

    Rain Sallow (/u/ta11ow) (@vexx32) Write-Output -NoEnumerate is not fully fixed in PS6.2.0 and up:

    See: #5122

    PS C:\Users\john.zabroski> ($PSVersionTable).PSVersion
    
    Major  Minor  Patch  PreReleaseLabel BuildLabel
    -----  -----  -----  --------------- ----------
    6      2      1
    
    PS C:\Users\john.zabroski> (Write-Output -NoEnumerate 1).GetType().FullName
    System.Collections.Generic.List`1[[System.Object, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
    
    PS C:\Users\john.zabroski> (1 | Write-Output -NoEnumerate).GetType().FullName
    System.Int32

    and also (I would argue the following is correct behavior, but just want to document it so that any fix to the above doesn't break this scenario):

    PS C:\Users\john.zabroski> (Write-Output -NoEnumerate @()).GetType().FullName
    System.Object[]
    

    The problem still exists for:

    • Direct argument
    • Not a collection

    The problem is fixed for:

    • Pipeline argument
    • Collection or scalar value
  6. vexx32 commented on Jun 28, 2019

    @vexx32
    Collaborator

    🤔 very curious. Okay. Will have to dig into that some...

  7. KevinMarquette commented on Nov 15, 2019

    @KevinMarquette
    Contributor

    I just ran into a scenario with this that gives an error on PowerShell 7 preview 5 but works fine on Windows PowerShell.

    $object = [pscustomobject]@{Name = 'Test'}
    $result = (Write-Output $object -NoEnumerate)
    $result.Name = 'New Name'
    

    Because $result is wrapped, I get this error:

    InvalidOperation:
    Line |
       3 | $result.Name = 'New Name'
         | ^ The property 'Name' cannot be found on this object. Verify that the property exists and can be set.
    

    I ran into this trying to get an existing module to work on PowerShell 7. So this is a simplified example of something I found in the wild.

  8. vexx32 commented on Nov 15, 2019

    @vexx32
    Collaborator

    Interesting. Looks like we still have some adjustments to make to the binder. Not sure where those changes would need to be made, but that scenario seems pretty clear we want to have that work. Dongbo Wang (@daxian-dbw) any thoughts?

  9. jzabroski commented on Nov 15, 2019

    @jzabroski

    Minimal repros on PSCore 6.2.1:

    PS C:\WINDOWS\system32> (Write-Output -NoEnumerate @()).GetType().FullName
    System.Object[]
    PS C:\WINDOWS\system32> $object = [pscustomobject]@{Name = 'Test'}
    PS C:\WINDOWS\system32> (Write-Output $object -NoEnumerate).GetType().FullName
    System.Collections.Generic.List`1[[System.Object, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
  10. vexx32 commented on Nov 15, 2019

    @vexx32
    Collaborator

    Confirmed that is the same on 7-preview.5.

    I think we may be able to fix this scenario by altering the binder to use List[PSObject] rather than List[object] -- by using List[object] here in binding the ValueFromRemainingArguments parameter, it looks like Write-Output is being forced to discard all ETS / instance members on any input objects. That doesn't strike me as a good behaviour at all.

    We should probably try to fix this for PS7 if we can, Steve Lee (@SteveL-MSFT)?

  11. 5 remaining items

  12. vexx32 commented on Nov 15, 2019

    @vexx32
    Collaborator

    I might just try taking a stab at fixing it and seeing if my assumption is correct or causes some other problem I'm not expecting. Are you familiar with where this handling for ValueFromRemainingArguments takes place Dongbo Wang (@daxian-dbw)? It might be worth taking a look.

    I'd rather not wait till post-ps7 to fix Write-Output 😕 -- doing so likely guarantees folx recommend heavily against using it and/or even using ValueFromRemainingArguments to avoid these unpredictable behaviours.

  13. mklement0 commented on Jan 30, 2020

    @mklement0
    Contributor

    As for a workaround:

    Use -InputObject explicitly rather than positional parameter binding:

    # OK in v6.2+, thanks to -InputObject
    (Write-Output -NoEnumerate -InputObject 1).GetType().Name | Should -Be Int32

    This is a somewhat ironic reversal from Windows PowerShell, where the inverse workaround (omitting -InputObject) is required to make -NoEnumerate behave properly (with input collections).

  14. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  15. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  16. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  17. microsoft-github-policy-service commented on Nov 23, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-BugIssue has been identified as a bug in the productResolution-No ActivityIssue has had no activity for 6 months or moreWG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions