diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs index 06e8b3f7c6..b624c6e08c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs @@ -22,8 +22,6 @@ namespace Microsoft.PowerShell.Commands /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] - [Parameter(Position = 0, ParameterSetName = "PathWithRelativeBase", - Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { get @@ -42,8 +40,6 @@ namespace Microsoft.PowerShell.Commands /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Parameter(ParameterSetName = "LiteralPathWithRelativeBase", - Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] [Alias("PSPath", "LP")] public string[] LiteralPath { @@ -83,8 +79,7 @@ namespace Microsoft.PowerShell.Commands /// /// Gets or sets the path the resolved relative path should be based off. /// - [Parameter(Mandatory = true, ParameterSetName = "PathWithRelativeBase")] - [Parameter(Mandatory = true, ParameterSetName = "LiteralPathWithRelativeBase")] + [Parameter] public string RelativeBasePath { get @@ -94,7 +89,6 @@ namespace Microsoft.PowerShell.Commands set { - _relative = true; _relativeBasePath = value; } } @@ -121,52 +115,50 @@ namespace Microsoft.PowerShell.Commands /// protected override void BeginProcessing() { - if (_relative) + if (!string.IsNullOrEmpty(RelativeBasePath)) { - if (!string.IsNullOrEmpty(RelativeBasePath)) + try { - try - { - _relativeBasePath = SessionState.Internal.Globber.GetProviderPath(RelativeBasePath, CmdletProviderContext, out _, out _relativeDrive); - } - catch (ProviderNotFoundException providerNotFound) - { - ThrowTerminatingError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - } - catch (DriveNotFoundException driveNotFound) - { - ThrowTerminatingError( - new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - } - catch (ProviderInvocationException providerInvocation) - { - ThrowTerminatingError( - new ErrorRecord( - providerInvocation.ErrorRecord, - providerInvocation)); - } - catch (NotSupportedException notSupported) - { - ThrowTerminatingError( - new ErrorRecord(notSupported, "ProviderIsNotNavigationCmdletProvider", ErrorCategory.InvalidArgument, RelativeBasePath)); - } - catch (InvalidOperationException invalidOperation) - { - ThrowTerminatingError( - new ErrorRecord(invalidOperation, "InvalidHomeLocation", ErrorCategory.InvalidOperation, RelativeBasePath)); - } - - return; + _relativeBasePath = SessionState.Internal.Globber.GetProviderPath(RelativeBasePath, CmdletProviderContext, out _, out _relativeDrive); + } + catch (ProviderNotFoundException providerNotFound) + { + ThrowTerminatingError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + } + catch (DriveNotFoundException driveNotFound) + { + ThrowTerminatingError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + } + catch (ProviderInvocationException providerInvocation) + { + ThrowTerminatingError( + new ErrorRecord( + providerInvocation.ErrorRecord, + providerInvocation)); + } + catch (NotSupportedException notSupported) + { + ThrowTerminatingError( + new ErrorRecord(notSupported, "ProviderIsNotNavigationCmdletProvider", ErrorCategory.InvalidArgument, RelativeBasePath)); + } + catch (InvalidOperationException invalidOperation) + { + ThrowTerminatingError( + new ErrorRecord(invalidOperation, "InvalidHomeLocation", ErrorCategory.InvalidOperation, RelativeBasePath)); } + return; + } + else if (_relative) + { _relativeDrive = SessionState.Path.CurrentLocation.Drive; _relativeBasePath = SessionState.Path.CurrentLocation.ProviderPath; - return; } } @@ -181,7 +173,25 @@ namespace Microsoft.PowerShell.Commands Collection result = null; try { - result = SessionState.Path.GetResolvedPSPathFromPSPath(path, CmdletProviderContext); + if (MyInvocation.BoundParameters.ContainsKey("RelativeBasePath")) + { + // Pushing and popping the location is done because GetResolvedPSPathFromPSPath uses the current path to resolve relative paths. + // It's important that we pop the location before writing an object to the pipeline to avoid affecting downstream commands. + try + { + SessionState.Path.PushCurrentLocation(string.Empty); + _ = SessionState.Path.SetLocation(_relativeBasePath); + result = SessionState.Path.GetResolvedPSPathFromPSPath(path, CmdletProviderContext); + } + finally + { + _ = SessionState.Path.PopLocation(string.Empty); + } + } + else + { + result = SessionState.Path.GetResolvedPSPathFromPSPath(path, CmdletProviderContext); + } if (_relative) { 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 91a16eb507..efd2441e0a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1 @@ -48,8 +48,70 @@ Describe "Resolve-Path returns proper path" -Tag "CI" { Pop-Location } } - It 'Resolve-Path should support user specified base paths' { - $Expected = Join-Path -Path .\ -ChildPath fakeroot - Resolve-Path -Path $fakeRoot -RelativeBasePath $testRoot | Should -BeExactly $Expected + It 'Resolve-Path RelativeBasePath should handle ' -TestCases @( + @{ + Scenario = "Absolute Path, Absolute ReleativeBasePath" + Path = $root + Basepath = $testRoot + Expected = $root, ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot" + CD = $null + } + @{ + Scenario = "Relative Path, Absolute ReleativeBasePath" + Path = ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot" + Basepath = $testRoot + Expected = $root, ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot" + CD = $null + } + @{ + Scenario = "Relative Path, Relative ReleativeBasePath" + Path = ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot" + Basepath = ".$([System.IO.Path]::DirectorySeparatorChar)" + Expected = $root, ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot" + CD = $testRoot + } + @{ + Scenario = "Invalid Path, Absolute ReleativeBasePath" + Path = Join-Path $testRoot ThisPathDoesNotExist + Basepath = $root + Expected = $null + CD = $null + } + @{ + Scenario = "Invalid Path, Invalid ReleativeBasePath" + Path = Join-Path $testRoot ThisPathDoesNotExist + Basepath = Join-Path $testRoot ThisPathDoesNotExist + Expected = $null + CD = $null + } + ) -Test { + param($Path, $BasePath, $Expected, $CD) + + if ($null -eq $Expected) + { + {Resolve-Path -Path $Path -RelativeBasePath $BasePath -ErrorAction Stop} | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.ResolvePathCommand" + {Resolve-Path -Path $Path -RelativeBasePath $BasePath -ErrorAction Stop -Relative} | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.ResolvePathCommand" + } + else + { + try + { + $OldLocation = if ($null -ne $CD) + { + $PWD + Set-Location $CD + } + + (Resolve-Path -Path $Path -RelativeBasePath $BasePath).ProviderPath | Should -BeExactly $Expected[0] + Resolve-Path -Path $Path -RelativeBasePath $BasePath -Relative | Should -BeExactly $Expected[1] + } + finally + { + if ($null -ne $OldLocation) + { + Set-Location $OldLocation + } + } + } } }