diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs index 140c4c3e1..6f260a89f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs @@ -105,13 +105,26 @@ namespace Microsoft.PowerShell.Commands { foreach (PathInfo currentPath in result) { + // When result path and base path is on different PSDrive + // (../)*path should not go beyond the root of base path + if (currentPath.Drive != SessionState.Path.CurrentLocation.Drive && + SessionState.Path.CurrentLocation.Drive != null && + !currentPath.ProviderPath.StartsWith( + SessionState.Path.CurrentLocation.Drive.Root, StringComparison.OrdinalIgnoreCase)) + { + WriteObject(currentPath.Path, enumerateCollection: false); + continue; + } string adjustedPath = SessionState.Path.NormalizeRelativePath(currentPath.Path, SessionState.Path.CurrentLocation.ProviderPath); - if (!adjustedPath.StartsWith(".", StringComparison.OrdinalIgnoreCase)) + // Do not insert './' if result path is not relative + if (!adjustedPath.StartsWith( + currentPath.Drive?.Root ?? currentPath.Path, StringComparison.OrdinalIgnoreCase) && + !adjustedPath.StartsWith(".", StringComparison.OrdinalIgnoreCase)) { adjustedPath = SessionState.Path.Combine(".", adjustedPath); } - WriteObject(adjustedPath, false); + WriteObject(adjustedPath, enumerateCollection: false); } } } @@ -150,7 +163,7 @@ namespace Microsoft.PowerShell.Commands if (!_relative) { - WriteObject(result, true); + WriteObject(result, enumerateCollection: true); } } } // ProcessRecord diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 index e5c5533a2..9494c1ed9 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 @@ -1,6 +1,25 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. Describe "Resolve-Path returns proper path" -Tag "CI" { + BeforeAll { + $driveName = "RvpaTest" + $root = Join-Path $TestDrive "fakeroot" + $file = Join-Path $root "file.txt" + $null = New-Item -Path $root -ItemType Directory -Force + $null = New-Item -Path $file -ItemType File -Force + $null = New-PSDrive -Name $driveName -PSProvider FileSystem -Root $root + + $testRoot = Join-Path $TestDrive "" + $fakeRoot = Join-Path "$driveName`:" "" + + $relCases = @( + @{ wd = $fakeRoot; target = $testRoot; expected = $testRoot } + @{ wd = $testRoot; target = Join-Path $fakeRoot "file.txt"; expected = Join-Path "." "fakeroot" "file.txt" } + ) + } + AfterAll { + Remove-PSDrive -Name $driveName -Force + } It "Resolve-Path returns resolved paths" { Resolve-Path $TESTDRIVE | Should -BeExactly "$TESTDRIVE" } @@ -19,4 +38,14 @@ Describe "Resolve-Path returns proper path" -Tag "CI" { $result = Resolve-Path -LiteralPath "TestDrive:\\\\\" ($result.Path.TrimEnd('/\')) | Should -BeExactly "TestDrive:" } + It "Resolve-Path -Relative '' should return correct path on ''" -TestCases $relCases { + param($wd, $target, $expected) + try { + Push-Location -Path $wd + Resolve-Path -Path $target -Relative | Should -BeExactly $expected + } + finally { + Pop-Location + } + } }