diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs
index 905a82c8e86..06e8b3f7c69 100644
--- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs
+++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs
@@ -22,6 +22,8 @@ public class ResolvePathCommand : CoreCommandWithCredentialsBase
///
[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
@@ -40,6 +42,8 @@ public string[] Path
///
[Parameter(ParameterSetName = "LiteralPath",
Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]
+ [Parameter(ParameterSetName = "LiteralPathWithRelativeBase",
+ Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]
[Alias("PSPath", "LP")]
public string[] LiteralPath
{
@@ -59,7 +63,8 @@ public string[] LiteralPath
/// Gets or sets the value that determines if the resolved path should
/// be resolved to its relative version.
///
- [Parameter()]
+ [Parameter(ParameterSetName = "Path")]
+ [Parameter(ParameterSetName = "LiteralPath")]
public SwitchParameter Relative
{
get
@@ -75,6 +80,25 @@ public SwitchParameter Relative
private SwitchParameter _relative;
+ ///
+ /// Gets or sets the path the resolved relative path should be based off.
+ ///
+ [Parameter(Mandatory = true, ParameterSetName = "PathWithRelativeBase")]
+ [Parameter(Mandatory = true, ParameterSetName = "LiteralPathWithRelativeBase")]
+ public string RelativeBasePath
+ {
+ get
+ {
+ return _relativeBasePath;
+ }
+
+ set
+ {
+ _relative = true;
+ _relativeBasePath = value;
+ }
+ }
+
#endregion Parameters
#region parameter data
@@ -84,10 +108,68 @@ public SwitchParameter Relative
///
private string[] _paths;
+ private PSDriveInfo _relativeDrive;
+ private string _relativeBasePath;
+
#endregion parameter data
#region Command code
+ ///
+ /// Finds the path and drive that should be used for relative path resolution
+ /// represents.
+ ///
+ protected override void BeginProcessing()
+ {
+ if (_relative)
+ {
+ if (!string.IsNullOrEmpty(RelativeBasePath))
+ {
+ 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;
+ }
+
+ _relativeDrive = SessionState.Path.CurrentLocation.Drive;
+ _relativeBasePath = SessionState.Path.CurrentLocation.ProviderPath;
+ return;
+ }
+ }
+
///
/// Resolves the path containing glob characters to the PowerShell paths that it
/// represents.
@@ -109,10 +191,9 @@ protected override void ProcessRecord()
{
// 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))
+ if (currentPath.Drive != _relativeDrive &&
+ _relativeDrive != null &&
+ !currentPath.ProviderPath.StartsWith(_relativeDrive.Root, StringComparison.OrdinalIgnoreCase))
{
WriteObject(currentPath.Path, enumerateCollection: false);
continue;
@@ -127,8 +208,7 @@ protected override void ProcessRecord()
}
baseCache = basePath;
- string adjustedPath = SessionState.Path.NormalizeRelativePath(currentPath.Path,
- SessionState.Path.CurrentLocation.ProviderPath);
+ string adjustedPath = SessionState.Path.NormalizeRelativePath(currentPath.Path, _relativeBasePath);
// Do not insert './' if result path is not relative
if (!adjustedPath.StartsWith(
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 87195c26352..91a16eb507b 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Resolve-Path.Tests.ps1
@@ -48,4 +48,8 @@ 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
+ }
}