From fbfbb4f005077883c5f50fbf8524d1ac362ab024 Mon Sep 17 00:00:00 2001 From: kwkam Date: Sun, 5 Aug 2018 20:31:06 +0800 Subject: [PATCH] [Feature] Fix Move-Item -Path with wildcard char (#7397) Unescape non-literal, non-glob path in ProccessRecord and set the context.SuppressWildcardExpansion in RenameItem. This solve the issue where Rename-Item complains -Path does not exist when both -Path and CWD contains special characters. --- .../commands/management/Navigation.cs | 288 +++++++++--------- .../Move-Item.Tests.ps1 | 10 + 2 files changed, 150 insertions(+), 148 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs index d357e1bd0d..a58d0963d8 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs @@ -3225,7 +3225,7 @@ namespace Microsoft.PowerShell.Commands { if (base.SuppressWildcardExpansion) { - MoveItem(path); + MoveItem(path, literalPath: true); } else { @@ -3234,173 +3234,165 @@ namespace Microsoft.PowerShell.Commands foreach (PathInfo resolvedPathInfo in resolvedPaths) { string resolvedPath = resolvedPathInfo.Path; - MoveItem(resolvedPath); + MoveItem(resolvedPath, literalPath: true); } } } - } // ProcessRecord + } - private void MoveItem(string path) + private void MoveItem(string path, bool literalPath = false) { CmdletProviderContext currentContext = CmdletProviderContext; + currentContext.SuppressWildcardExpansion = literalPath; - do + try { - try - { - string escapedPath = path; - if (!base.SuppressWildcardExpansion) { escapedPath = WildcardPattern.Escape(path); } - if (!InvokeProvider.Item.Exists(escapedPath, currentContext)) - { - PSInvalidOperationException invalidOperation = - (PSInvalidOperationException) - PSTraceSource.NewInvalidOperationException( - NavigationResources.MoveItemDoesntExist, - path); - - WriteError( - new ErrorRecord( - invalidOperation.ErrorRecord, - invalidOperation)); - continue; - } - } - catch (PSNotSupportedException notSupported) - { - WriteError( - new ErrorRecord( - notSupported.ErrorRecord, - notSupported)); - continue; - } - catch (DriveNotFoundException driveNotFound) - { - WriteError( - new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - continue; - } - catch (ProviderNotFoundException providerNotFound) - { - WriteError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - continue; - } - catch (ItemNotFoundException pathNotFound) - { - WriteError( - new ErrorRecord( - pathNotFound.ErrorRecord, - pathNotFound)); - continue; - } - - // See if the item to be moved is in use. - bool isCurrentLocationOrAncestor = false; - try - { - isCurrentLocationOrAncestor = SessionState.Path.IsCurrentLocationOrAncestor(path, currentContext); - } - catch (PSNotSupportedException notSupported) - { - WriteError( - new ErrorRecord( - notSupported.ErrorRecord, - notSupported)); - continue; - } - catch (DriveNotFoundException driveNotFound) - { - WriteError( - new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - continue; - } - catch (ProviderNotFoundException providerNotFound) - { - WriteError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - continue; - } - catch (ItemNotFoundException pathNotFound) - { - WriteError( - new ErrorRecord( - pathNotFound.ErrorRecord, - pathNotFound)); - continue; - } - - if (isCurrentLocationOrAncestor) + if (!InvokeProvider.Item.Exists(path, currentContext)) { PSInvalidOperationException invalidOperation = (PSInvalidOperationException) PSTraceSource.NewInvalidOperationException( - NavigationResources.MoveItemInUse, + NavigationResources.MoveItemDoesntExist, path); WriteError( new ErrorRecord( invalidOperation.ErrorRecord, invalidOperation)); - continue; - } - - // Default to the CmdletProviderContext that will direct output to - // the pipeline. - - CmdletProviderContext currentCommandContext = currentContext; - currentCommandContext.PassThru = PassThru; - - tracer.WriteLine("Moving {0} to {1}", path, Destination); - - try - { - // Now do the move - string escapedPath = path; - if (!base.SuppressWildcardExpansion) { escapedPath = WildcardPattern.Escape(path); } - InvokeProvider.Item.Move(escapedPath, Destination, currentCommandContext); - } - catch (PSNotSupportedException notSupported) - { - WriteError( - new ErrorRecord( - notSupported.ErrorRecord, - notSupported)); - continue; - } - catch (DriveNotFoundException driveNotFound) - { - WriteError( - new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - continue; - } - catch (ProviderNotFoundException providerNotFound) - { - WriteError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - continue; - } - catch (ItemNotFoundException pathNotFound) - { - WriteError( - new ErrorRecord( - pathNotFound.ErrorRecord, - pathNotFound)); - continue; + return; } } - while (false); + catch (PSNotSupportedException notSupported) + { + WriteError( + new ErrorRecord( + notSupported.ErrorRecord, + notSupported)); + return; + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + return; + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + return; + } + catch (ItemNotFoundException pathNotFound) + { + WriteError( + new ErrorRecord( + pathNotFound.ErrorRecord, + pathNotFound)); + return; + } + + // See if the item to be moved is in use. + bool isCurrentLocationOrAncestor = false; + try + { + isCurrentLocationOrAncestor = SessionState.Path.IsCurrentLocationOrAncestor(path, currentContext); + } + catch (PSNotSupportedException notSupported) + { + WriteError( + new ErrorRecord( + notSupported.ErrorRecord, + notSupported)); + return; + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + return; + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + return; + } + catch (ItemNotFoundException pathNotFound) + { + WriteError( + new ErrorRecord( + pathNotFound.ErrorRecord, + pathNotFound)); + return; + } + + if (isCurrentLocationOrAncestor) + { + PSInvalidOperationException invalidOperation = + (PSInvalidOperationException) + PSTraceSource.NewInvalidOperationException( + NavigationResources.MoveItemInUse, + path); + + WriteError( + new ErrorRecord( + invalidOperation.ErrorRecord, + invalidOperation)); + return; + } + + // Default to the CmdletProviderContext that will direct output to + // the pipeline. + + currentContext.PassThru = PassThru; + + tracer.WriteLine("Moving {0} to {1}", path, Destination); + + try + { + // Now do the move + InvokeProvider.Item.Move(path, Destination, currentContext); + } + catch (PSNotSupportedException notSupported) + { + WriteError( + new ErrorRecord( + notSupported.ErrorRecord, + notSupported)); + return; + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + return; + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + return; + } + catch (ItemNotFoundException pathNotFound) + { + WriteError( + new ErrorRecord( + pathNotFound.ErrorRecord, + pathNotFound)); + return; + } } #endregion Command code diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Move-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Move-Item.Tests.ps1 index d9a71cdbcc..95d6538fb6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Move-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Move-Item.Tests.ps1 @@ -6,6 +6,10 @@ Describe "Move-Item tests" -Tag "CI" { Setup -f originalfile.txt -content "This is content" $source = "$TESTDRIVE/originalfile.txt" $target = "$TESTDRIVE/ItemWhichHasBeenMoved.txt" + Setup -f [orig-file].txt -content "This is not content" + $sourceSp = "$TestDrive/``[orig-file``].txt" + $targetSpName = "$TestDrive/ItemWhichHasBeen[Moved].txt" + $targetSp = "$TestDrive/ItemWhichHasBeen``[Moved``].txt" } It "Move-Item will move a file" { Move-Item $source $target @@ -13,6 +17,12 @@ Describe "Move-Item tests" -Tag "CI" { $target | Should -Exist "$target" | Should -FileContentMatchExactly "This is content" } + It "Move-Item will move a file when path contains special char" { + Move-Item $sourceSp $targetSpName + $sourceSp | Should -Not -Exist + $targetSp | Should -Exist + $targetSp | Should -FileContentMatchExactly "This is not content" + } Context "Move-Item with filters" { BeforeAll {