Skip to content

Get-FormatData doesn't report formatting data for some types for which formatting data ships with PowerShell. #4237

Description

I haven't looked into the logic behind which types' formatting data isn't being reported, but two examples are below.

A counter example is Get-FormatData System.Management.Automation.AliasInfo, which works as expected.

Steps to reproduce

Get-FormatData System.IO.DirectoryInfo, System.IO.FileInfo

Expected behavior

[System.Management.Automation.ExtendedTypeDefinition] instances describing the formatting, as usual.

Actual behavior

No output is produced; $? indicates $True.

Yet, formatting data is clearly in effect.

In Windows PowerShell, it can be discovered as follows:

Select-String -List System.IO.DirectoryInfo, System.IO.FileInfo $PSHOME/*.ps1xml 

Environment data

PowerShell Core v6.0.0-beta.3 on macOS 10.12.5
PowerShell Core v6.0.0-beta.3 on Ubuntu 16.04.1 LTS
PowerShell Core v6.0.0-beta.3 on Microsoft Windows 10 Pro (64-bit; v10.0.14393)
Windows PowerShell v5.1.15063.413 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)

Activity

  1. lzybkr commented on Jul 13, 2017

    @lzybkr
    Contributor

    This is a bug, but the repro should be:

    Get-FormatData System.IO.DirectoryInfo, System.IO.FileInfo -PowerShellVersion 5.1

    This extra parameter was added in 5.1 so remoting would work between older clients and newer servers. The format data returned before 5.1 was incomplete and in some ways wrong, e.g. the file system types were returned as FileSystemTypes and it didn't actually work - the real type names were lost.

    That said, there is still a bug, I'm not quite sure where it is though.

  2. lzybkr commented on Jul 13, 2017

    @lzybkr
    Contributor

    I should add - the format data for help is intentionally never returned - I forget the exact reason I did that - I think there were problems with serialization depth being exceeded and I decided it wasn't important to return those formats anyway.

  3. added
    WG-Enginecore PowerShell engine, interpreter, and runtime
    Issue-BugIssue has been identified as a bug in the product
    on Jul 13, 2017
  4. mklement0 commented on Jul 25, 2017

    @mklement0
    ContributorAuthor

    Jason Shirk (@lzybkr)

    Thanks for clarifying, but just so I get the full picture:

    Are you saying that even with the bug fixed it will be necessary to add -PowerShellVersion 5.1 to Get-FormatData calls in order to get output?

    Since something like Get-FormatData System.Management.Automation.AliasInfo currently works as-is, to what types - other than the 2 mentioned (System.IO.DirectoryInfo, System.IO.FileInfo) - does this requirement to specify -PowerShellVersion apply?

    Is there an explicit list or some abstract criterion?

  5. lzybkr commented on Jul 25, 2017

    @lzybkr
    Contributor

    In the abstract - some format data properties were missing before 5.1. If those properties were non-null, then the format data returned by Get-FormatData couldn't have been used correctly, so those types are not returned.

    To be concrete, look at the implementations of PSControl.CompatibleWithOldPowerShell

    Briefly, I think GroupBy, SelectCondition, and CustomControl are the items that trigger not getting returned by Get-FormatData unless you specify -PowerShellVersion 5.1.

  6. SteveL-MSFT commented on Nov 28, 2017

    @SteveL-MSFT
    Member

    The user should not have to specify anything and by default it should show all the formatters perhaps with a PowerShellVersion column. I believe -PowerShellVersion exists for remoting.

  7. lzybkr commented on Nov 28, 2017

    @lzybkr
    Contributor

    If it's possible to detect how Get-FormatData is called, then it would be possible to return all formatters with no arguments, but only when called locally. If called from a remote client, then it's important to determine the client version and not return objects that won't deserialize.

    I'm not aware of any cmdlet that does something like this today, so I'm not sure how easy it would be.

  8. SteveL-MSFT commented on Oct 20, 2018

    @SteveL-MSFT
    Member

    Paul Higinbotham (@PaulHigin) are you aware of there is a way for a cmdlet to detect it is being remotely?

  9. mklement0 commented on Sep 23, 2019

    @mklement0
    ContributorAuthor

    Steve Lee (@SteveL-MSFT):

    You can test if the automatic $PSSenderInfo variable is present, which is only defined in remoting sessions. (For additional robustness, you can test whether its type is System.Management.Automation.Remoting.PSSenderInfo, given that PowerShell doesn't prevent you from manually assigning to this variable in local sessions).

    Please note that PR #8063 didn't fix this issue, only a closely related one, so can you please re-open this one?

    The issue is still that you shouldn't have to use -PowerShellVersion just so you can see the current session's formatting data reliably.

  10. 1 remaining item

  11. lzybkr commented on Nov 22, 2019

    @lzybkr
    Contributor

    Thomas Nieto (@ThomasNieto) - the default value for a remote session must be compatible with older clients that are unaware of the parameter and hence do not specify it. This include Windows PowerShell v5.0 and earlier.

    For the local case, maybe a different default is possible.

  12. SteveL-MSFT commented on Nov 22, 2019

    @SteveL-MSFT
    Member

    Paul Higinbotham (@PaulHigin), would what Michael Klement (@mklement0) proposes here work to detect remote usage?

  13. mklement0 commented on Nov 22, 2019

    @mklement0
    ContributorAuthor

    Sorry, Steve Lee (@SteveL-MSFT): my previous attempt to distinguish true remoting from background jobs was flawed.

    I hope the following works robustly.

    Please note the assumption made in the comments, which should be confirmed.


    From what I can tell, all that is needed is to replace this:

    bool writeOldWay = PowerShellVersion == null ||
    PowerShellVersion.Major < 5 ||
    (PowerShellVersion.Major == 5 && PowerShellVersion.Minor < 1);

    with this:

    // $PSSenderInfo is defined in true remoting contexts and background jobs.
    // Its Boolean .PSShowComputerName NoteProperty is false only in background jobs.
    bool remoting = (GetVariableValue("PSSenderInfo") as PSObject)?.Properties["PSShowComputerName"]?.Value is bool value && value;
    bool writeOldWay = remoting && (
                        PowerShellVersion == null ||
                        PowerShellVersion.Major < 5 ||
                        (PowerShellVersion.Major == 5 && PowerShellVersion.Minor < 1)
                        );
  14. PaulHigin commented on Nov 25, 2019

    @PaulHigin
    Contributor

    This is probably the best way to detect whether a cmdlet is running within a remote session in general.
    But if this is a built-in cmdlet that has access to internal types the following will also work:

    bool remoting = (this.Context.InternalHost.ExternalHost is ServerRemoteHost);
    
  15. mklement0 commented on Nov 25, 2019

    @mklement0
    ContributorAuthor

    Paul Higinbotham (@PaulHigin), but won't that return true for local-machine background jobs as well, which I presume we do not want?

  16. PaulHigin commented on Nov 25, 2019

    @PaulHigin
    Contributor

    You still have the version check. Background jobs will always run the current version of PowerShell.

  17. mklement0 commented on Nov 25, 2019

    @mklement0
    ContributorAuthor

    Background jobs will always run the current version of PowerShell.

    Yes, which is why the version check shouldn't be done for background jobs, as in my code above.

    If you only check for the host, you'll get a false positive for background jobs, given that true remoting and background jobs both use the ServerRemoteHost host.

  18. PaulHigin commented on Nov 25, 2019

    @PaulHigin
    Contributor

    I guess I'm confused. You will never have a background job with version < 5.1, so the write is always the new way. Isn't that what we want?

  19. mklement0 commented on Nov 25, 2019

    @mklement0
    ContributorAuthor

    Note the PowerShellVersion == null part of the original conditional, which means that the "old way" kicks in in the absence of a -PowerShellVersion argument as well.

    That is, currently you always get the "old way" if you don't explicitly specify -PowerShellVersion 5.1 or higher - this awkward requirement is what prompted creation of this issue.

    Therefore, we must ensure that background jobs aren't mistaken for remoting.

  20. mklement0 commented on Nov 25, 2019

    @mklement0
    ContributorAuthor

    Paul Higinbotham (@PaulHigin), I think you may be missing that PowerShellVersion refers to a parameter, not to the executing PowerShell engine's version.

  21. PaulHigin commented on Nov 26, 2019

    @PaulHigin
    Contributor

    Yes, you are right. I think your code is the correct way.

  22. added a commit that references this issue on Dec 5, 2019
    69dfafe
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-FixedThe issue is fixed.WG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions