You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Stringification behavior of FileInfo / Directory instances has changed since v6.0.2 #7132
How FileInfo / DirectoryInfo instances stringify implicitly used to depend on the specifics of the Get-ChildItem call that emitted them.
Previously, a Get-ChildItem command that targeted a directory path only would yield child items that stringified to their mere name rather than to their full path.
This now behaves differently in PowerShell Core v6.1.0-preview.3.
While the new behavior is more predictable and would actually resolve part of #6057, it is a - presumably unintended - breaking change.
Steps to reproduce
Create a temp. dir tmpDir with single file tmpFile, then use Get-ChildItem to enumerate tmpDir and stringify the resulting item:
changed the title [-]Stringification behavior of FileInfo instances has changed since v6.0.2[/-][+]Stringification behavior of FileInfo / Directory instances has changed since v6.0.2[/+]on Jun 21, 2018
Thanks, but I don't think that explains it. The only .ToString()-relevant change in that commit is to remove the transformation of a path like c: (i.e., a drive-letter-only path) to . via the now-removed ShouldReviseDirectoryPathToCurrent() method, something that the commit message calls a "limited trust holdover".
The fundamental behavior hasn't changed: whatever path you pass in to construct the instance is output by .ToString().
Thus, something on the PowerShell side must have changed:
Ilya (@iSazonov), when you say "now we call obj.ToString()", can you point us to the relevant code?
ETS meaning extended type system? So some kind of script method override? (This is what I was imagining too).
PSScriptAnalyzer doesn't currently have any single rule tracking semantic changes in PowerShell. I think that kind of effort could only really proceed with help from PowerShell. I think we've discussed exactly this before, the idea where we have a big rule that just looks up the PowerShell version and checks the particular syntax.
If we can at least catalogue the nature of any and all breaking changes in one place, such a rule would be feasible to write.
Also, I feel I should register that despite making the opposing case, I'm actually in favour of the new behaviour.
Recommendation is to explore an ETS solution and measure the level of compatibility as well as the perf impact before agreeing that would be the final solution.
ETS won't be helpful to retain the old behavior in PowerShell. As described in #7132 (comment), the root cause of the original inconsistent behavior in PowerShell is the inconsistency in returning result of FileInfo.ToString(). When invoking Get-ChildItem against a directory, it uses DirectoryInfo.EnumerateFiles() to get the FileInfo objects, which return the file name only when calling ToString() on them. When invoking Get-ChildItem against files directly, it uses the public constructor new FileInfo(string fileName) to create the FileInfo objects, which return the full path when calling ToString() on them.
So to retain the old wrong behavior, we will have to put some hacky code in FileSystemProvider to differentiate the FileInfo objects generated from Get-ChildItem <dir> and Get-ChildItem <file> and Get-Item <file>. That code would be definitely confusing and I don't think we should do that just in order to retain an unfavorable existing behavior. Since .NET accepted the breaking change by fixing the inconsistency, it's a good chance for us to do the same.
Reacted by Rain Sallow (/u/ta11ow), Ilya, Patrick Meinecke and Michael Klement
I don't think it makes sense to retain the more confusing behaviour just because people are accustomed to dealing with it.
Keeping this change means some scripts will break, maybe, but in fixing those we'd just be removing additional workaround logic that was probably more annoying to have around anyway.
Maybe a small handful of edge cases where it really was helpful, but there is no shortage of available alternatives for those, either. 🙂
@PowerShell/powershell-committee reviewed this. The work involved to maintain compatibility is not worth the effort as the underlying platform has introduced a change to fix an inconsistency problem. This results in a breaking change for some PowerShell users, but detecting of this will be quick and using .FullName or .Name as appropriate is the right thing to do. We could make a change in Join-Path to support joining two absolute paths to make this simpler for scripts, but that would be a separate issue.
Reacted by Rain Sallow (/u/ta11ow), Michael Klement and Ilya
Activity
[-]in:title get-childitem[/-][+]Stringification behavior of FileInfo instances has changed since v6.0.2[/+][-]Stringification behavior of FileInfo instances has changed since v6.0.2[/-][+]Stringification behavior of FileInfo / Directory instances has changed since v6.0.2[/+]iSazonov commentedon Jun 21, 2018
I think it come from .Net Core 2.0 -> 2.1 update.
mklement0 commentedon Jun 21, 2018
Ilya (@iSazonov):
Probably not, given that the behavior in your examples is no different from the one in Windows PowerShell v2 - v5.1 .
Something must have changed in the way PowerShell constructs such instances.
iSazonov commentedon Jun 22, 2018
I can confirm that now we call obj.ToString() for FileInfo objects but I can't find what's changed in code.
SeeminglyScience commentedon Jun 26, 2018
Just ran into this as well.
Here's the commit in corefx where the ToString behavior was changed.Here's that line specifically.Edit: nvm, not at all relevant :)mklement0 commentedon Jun 26, 2018
Patrick Meinecke (@SeeminglyScience):
Thanks, but I don't think that explains it. The only
.ToString()-relevant change in that commit is to remove the transformation of a path likec:(i.e., a drive-letter-only path) to.via the now-removedShouldReviseDirectoryPathToCurrent()method, something that the commit message calls a "limited trust holdover".The fundamental behavior hasn't changed: whatever path you pass in to construct the instance is output by
.ToString().Thus, something on the PowerShell side must have changed:
Ilya (@iSazonov), when you say "now we call obj.ToString()", can you point us to the relevant code?
iSazonov commentedon Jun 26, 2018
I don't remember already but seems it is here https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/MshObject.cs#L1244
and in the case we do https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/MshObject.cs#L1332
rjmholt commentedon Jun 6, 2019
Copying some things from the duplicate issue I just closed...
Looks like .NET is leaning toward WontFix.
We should:
More info in https://github.com/dotnet/corefx/issues/38215.
/cc Steve Lee (@SteveL-MSFT) and Joey Aiello (@joeyaiello) since we should amend changelogs.
Also tagging for @PowerShell/powershell-committee review
rjmholt commentedon Jun 6, 2019
.NET team verified a change of theirs broke this. I have a repro in the issue I opened in CoreFX
17 remaining items
iSazonov commentedon Jun 13, 2019
If .Net Core found this accessible we could do the same.
Perhaps PSSA could help. /cc Rob Holt (@rjmholt) Christoph Bergmeister (@bergmeister)
Not clear about ETS. I'd expect that we fix only
diroutput in formatting system.rjmholt commentedon Jun 13, 2019
ETS meaning extended type system? So some kind of script method override? (This is what I was imagining too).
PSScriptAnalyzer doesn't currently have any single rule tracking semantic changes in PowerShell. I think that kind of effort could only really proceed with help from PowerShell. I think we've discussed exactly this before, the idea where we have a big rule that just looks up the PowerShell version and checks the particular syntax.
If we can at least catalogue the nature of any and all breaking changes in one place, such a rule would be feasible to write.
Also, I feel I should register that despite making the opposing case, I'm actually in favour of the new behaviour.
iSazonov commentedon Jun 13, 2019
Yes.
Have we a tracking issue?
daxian-dbw commentedon Jun 13, 2019
ETS won't be helpful to retain the old behavior in PowerShell. As described in #7132 (comment), the root cause of the original inconsistent behavior in PowerShell is the inconsistency in returning result of
FileInfo.ToString(). When invokingGet-ChildItemagainst a directory, it usesDirectoryInfo.EnumerateFiles()to get theFileInfoobjects, which return the file name only when callingToString()on them. When invokingGet-ChildItemagainst files directly, it uses the public constructornew FileInfo(string fileName)to create theFileInfoobjects, which return the full path when callingToString()on them.So to retain the old wrong behavior, we will have to put some hacky code in
FileSystemProviderto differentiate theFileInfoobjects generated fromGet-ChildItem <dir>andGet-ChildItem <file>andGet-Item <file>. That code would be definitely confusing and I don't think we should do that just in order to retain an unfavorable existing behavior. Since .NET accepted the breaking change by fixing the inconsistency, it's a good chance for us to do the same.vexx32 commentedon Jun 13, 2019
I don't think it makes sense to retain the more confusing behaviour just because people are accustomed to dealing with it.
Keeping this change means some scripts will break, maybe, but in fixing those we'd just be removing additional workaround logic that was probably more annoying to have around anyway.
Maybe a small handful of edge cases where it really was helpful, but there is no shortage of available alternatives for those, either. 🙂
rjmholt commentedon Jun 13, 2019
#9138
SteveL-MSFT commentedon Jun 19, 2019
@PowerShell/powershell-committee reviewed this. The work involved to maintain compatibility is not worth the effort as the underlying platform has introduced a change to fix an inconsistency problem. This results in a breaking change for some PowerShell users, but detecting of this will be quick and using
.FullNameor.Nameas appropriate is the right thing to do. We could make a change inJoin-Pathto support joining two absolute paths to make this simpler for scripts, but that would be a separate issue.