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.
Get-FormatData System.IO.DirectoryInfo, System.IO.FileInfo
[System.Management.Automation.ExtendedTypeDefinition] instances describing the formatting, as usual.
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
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)
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.
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.
@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?
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.
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.
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.
@PaulHigin are you aware of there is a way for a cmdlet to detect it is being remotely?
@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.
When remoting needs to use a specific PSVersion does it always pass that parameter? If so, can we have -PowerShellVersion default value be $PSVersionTable.PSVersion solving this for local and remote use?
@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.
@PaulHigin, would what @mklement0 proposes here work to detect remote usage?
Sorry, @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:
with this:
c#
// $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)
);
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);
@PaulHigin, but won't that return true for local-machine _background jobs_ as well, which I presume we do _not_ want?
You still have the version check. Background jobs will always run the current version of PowerShell.
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.
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?
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.
@PaulHigin, I think you may be missing that PowerShellVersion refers to a _parameter_, not to the executing PowerShell engine's version.
Yes, you are right. I think your code is the correct way.
:tada:This issue was addressed in #11270, which has now been successfully released as v7.1.0-preview.2.:tada:
Handy links: