diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index cf833a7643b..0d6f2a97fa2 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -1324,8 +1324,8 @@ internal void GetChildItems( try { // If we're recursing, do some path fixups to match user - // expectations: - if (recurse) + // expectations, but only if the last part is a file and not a directory: + if (recurse && !path.EndsWith(Path.DirectorySeparatorChar) && !path.EndsWith(Path.AltDirectorySeparatorChar)) { string childName = GetChildName(path, context); diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 3f8c32a2fed..4e0d72765ce 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -1373,13 +1373,18 @@ private FileSystemInfo GetFileSystemItem(string path, ref bool isContainer, bool path = NormalizePath(path); FileInfo result = new FileInfo(path); - // FileInfo.Exists is always false for a directory path, so we check the attribute for existence. var attributes = result.Attributes; - if ((int)attributes == -1) { /* Path doesn't exist. */ return null; } - bool hidden = attributes.HasFlag(FileAttributes.Hidden); isContainer = attributes.HasFlag(FileAttributes.Directory); + // FileInfo allows for a file path to end in a trailing slash, but the resulting object + // is incomplete. A trailing slash should indicate a directory. So if the path ends in a + // trailing slash and is not a directory, return null + if (!isContainer && path.EndsWith(Path.DirectorySeparatorChar)) + { + return null; + } + FlagsExpression evaluator = null; FlagsExpression switchEvaluator = null; GetChildDynamicParameters fspDynamicParam = DynamicParameters as GetChildDynamicParameters; diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 index 5059928f322..a5d06df0b46 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 @@ -217,6 +217,17 @@ Describe "Get-ChildItem" -Tags "CI" { It "Should list the folder present when path length equal to MAX_PATH" { (Get-ChildItem -Path TestDrive:\$item_I -Recurse -Force).Name.Length | Should -BeGreaterThan 0 } + + It 'Trailing slash for -Path should treat it as a folder only when used with -recurse' { + $foo = New-Item -ItemType Directory -Path TestDrive:\foo + $foo2 = New-Item -ItemType Directory -Path TestDrive:\foo\foo + $bar = New-Item -ItemType File -Path TestDrive:\foo\bar + $bar2 = New-Item -ItemType File -Path TestDrive:\foo\foo\bar + + { Get-ChildItem -Path testdrive:/foo/bar/ -Recurse -ErrorAction Stop } | Should -Throw -ErrorId 'ItemNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand' + $barFiles = Get-ChildItem -Path testdrive:/foo/bar -Recurse + $barFiles.Count | Should -Be 2 + } } Context 'Env: Provider' {