From 0d37aaef73f1217d1a4d7221023a934ecb706b72 Mon Sep 17 00:00:00 2001 From: kwkam Date: Mon, 30 Jul 2018 20:47:11 +0800 Subject: [PATCH 01/10] [Feature] Fix New-Item -Path with wildcard char Unescape non-literal path when -Name is not set. This works around for New-Item treating -Path as literal path while it can also be globbable. For example, assuming there is "[file]1" in current directory, and tab completion suggests './`[file`]1' for the -Path argument, but > New-Item -Path './`[file`]2' will create a file named "`[file`]2" instead of "[file]2". --- .../engine/SessionStateContainer.cs | 2 +- .../New-Item.Tests.ps1 | 30 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index 546965c83cf..e8a002a54cb 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -3443,7 +3443,7 @@ internal void NewItem( if (string.IsNullOrEmpty(name)) { string providerPath = - Globber.GetProviderPath(resolvePath, context, out provider, out driveInfo); + Globber.GetProviderPath(WildcardPattern.Unescape(resolvePath), context, out provider, out driveInfo); providerInstance = GetProviderInstance(provider); providerPaths.Add(providerPath); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index a9a2599891b..fa245c16c53 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -34,16 +34,17 @@ function Clean-State Describe "New-Item" -Tags "CI" { $tmpDirectory = $TestDrive $testfile = "testfile.txt" + $testfileSp = "``[test``]file.txt" $testfolder = "newDirectory" $testsubfolder = "newSubDirectory" $testlink = "testlink" $FullyQualifiedFile = Join-Path -Path $tmpDirectory -ChildPath $testfile + $FullyQualifiedFileSp = Join-Path -Path $tmpDirectory -ChildPath $testfileSp $FullyQualifiedFolder = Join-Path -Path $tmpDirectory -ChildPath $testfolder $FullyQualifiedLink = Join-Path -Path $tmpDirectory -ChildPath $testlink $FullyQualifiedSubFolder = Join-Path -Path $FullyQualifiedFolder -ChildPath $testsubfolder $FullyQualifiedFileInFolder = Join-Path -Path $FullyQualifiedFolder -ChildPath $testfile - BeforeEach { Clean-State } @@ -103,6 +104,12 @@ Describe "New-Item" -Tags "CI" { Test-Path $FullyQualifiedFile | Should -BeTrue } + It "Should create a file with correct name when Name switch is not used and Path contains special char" { + New-Item -Path $FullyQualifiedFileSp -ItemType file + + $FullyQualifiedFileSp | Should -Exist + } + It "Should be able to create a multiple items in different directories" { $FullyQualifiedFile2 = Join-Path -Path $tmpDirectory -ChildPath test2.txt New-Item -ItemType file -Path $FullyQualifiedFile, $FullyQualifiedFile2 @@ -196,9 +203,15 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { $testfile = "testfile.txt" $testfolder = "newDirectory" $testlink = "testlink" + $testlinkSrcSpName = "[test]src" + $testlinkSrcSp = "``[test``]src" + $testlinkSpName = "[test]link" + $testlinkSp = "``[test``]link" $FullyQualifiedFile = Join-Path -Path $tmpDirectory -ChildPath $testfile $FullyQualifiedFolder = Join-Path -Path $tmpDirectory -ChildPath $testfolder $FullyQualifiedLink = Join-Path -Path $tmpDirectory -ChildPath $testlink + $FullyQualifiedLSrcSp = Join-Path -Path $tmpDirectory -ChildPath $testlinkSrcSp + $FullyQualifiedLinkSp = Join-Path -Path $tmpDirectory -ChildPath $testlinkSp $SymLinkMask = [System.IO.FileAttributes]::ReparsePoint $DirLinkMask = $SymLinkMask -bor [System.IO.FileAttributes]::Directory @@ -249,6 +262,21 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { Test-Path $FullyQualifiedLink | Should -BeFalse } + It "Should create symbolic link with name contains special char" { + $null = New-Item -Path $tmpDirectory -Name $testlinkSrcSpName -ItemType File + $FullyQualifiedLSrcSp | Should -Exist + + $null = New-Item -Path $FullyQualifiedLinkSp -Target $FullyQualifiedLSrcSp -ItemType SymbolicLink + $FullyQualifiedLinkSp | Should -Exist + + $expectedTarget = Join-Path $tmpDirectory $testlinkSrcSpName + + $fileInfo = Get-ChildItem $FullyQualifiedLinkSp + $fileInfo.Target | Should -Match ([regex]::Escape($expectedTarget)) + $fileInfo.LinkType | Should -BeExactly "SymbolicLink" + $fileInfo.Attributes -band $DirLinkMask | Should -BeExactly $SymLinkMask + } + It "New-Item -ItemType SymbolicLink should understand directory path ending with slash" { $folderName = [System.IO.Path]::GetRandomFileName() $symbolicLinkPath = New-Item -ItemType SymbolicLink -Path "$tmpDirectory/$folderName/" -Value "/bar/" From 38222e895d7185207804cafd3b61bdbc403c7f3d Mon Sep 17 00:00:00 2001 From: kwkam Date: Sun, 12 Aug 2018 09:20:37 +0800 Subject: [PATCH 02/10] Add test --- .../Remove-Item.Tests.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 index 5dcb6b9201b..20283a96763 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 @@ -3,7 +3,10 @@ Describe "Remove-Item" -Tags "CI" { $testpath = $TestDrive $testfile = "testfile.txt" + $testfileSpName = "[testfile].txt" + $testfileSp = "``[testfile``].txt" $testfilepath = Join-Path -Path $testpath -ChildPath $testfile + $testfilepathSp = Join-Path -Path $testpath -ChildPath $testfileSp Context "File removal Tests" { BeforeEach { New-Item -Name $testfile -Path $testpath -ItemType "file" -Value "lorem ipsum" -Force @@ -109,6 +112,14 @@ Describe "Remove-Item" -Tags "CI" { Test-Path (Join-Path -Path $testpath -ChildPath file1.wav) | Should -BeFalse Test-Path (Join-Path -Path $testpath -ChildPath file2.wav) | Should -BeFalse } + + It "Should be able to remove file when path contains special char" { + New-Item -Path $testpath -Name $testfileSpName -ItemType File -Force + $testfilepathSp | Should -Exist + + Remove-Item -Path $testfilepathSp + $testfilepathSp | Should -Not -Exist + } } Context "Directory Removal Tests" { From 97aca064e59350d16d8814bbfb7976618d0a1263 Mon Sep 17 00:00:00 2001 From: kwkam Date: Sat, 1 Sep 2018 04:09:54 +0800 Subject: [PATCH 03/10] Use named parameters in New-Item test --- .../Microsoft.PowerShell.Management/New-Item.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index fa245c16c53..0d4f1792edf 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -269,9 +269,9 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { $null = New-Item -Path $FullyQualifiedLinkSp -Target $FullyQualifiedLSrcSp -ItemType SymbolicLink $FullyQualifiedLinkSp | Should -Exist - $expectedTarget = Join-Path $tmpDirectory $testlinkSrcSpName + $expectedTarget = Join-Path -Path $tmpDirectory -ChildPath $testlinkSrcSpName - $fileInfo = Get-ChildItem $FullyQualifiedLinkSp + $fileInfo = Get-ChildItem -Path $FullyQualifiedLinkSp $fileInfo.Target | Should -Match ([regex]::Escape($expectedTarget)) $fileInfo.LinkType | Should -BeExactly "SymbolicLink" $fileInfo.Attributes -band $DirLinkMask | Should -BeExactly $SymLinkMask From 80b56736d2202f32e827284d4638523ee73fe690 Mon Sep 17 00:00:00 2001 From: kwkam Date: Fri, 11 Jan 2019 22:45:45 +0800 Subject: [PATCH 04/10] Cosmetic change on Remove-Item.Tests --- .../Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 index 20283a96763..b7a0a6bf6ff 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 @@ -1,11 +1,11 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. Describe "Remove-Item" -Tags "CI" { - $testpath = $TestDrive - $testfile = "testfile.txt" + $testpath = $TestDrive + $testfile = "testfile.txt" $testfileSpName = "[testfile].txt" - $testfileSp = "``[testfile``].txt" - $testfilepath = Join-Path -Path $testpath -ChildPath $testfile + $testfileSp = "``[testfile``].txt" + $testfilepath = Join-Path -Path $testpath -ChildPath $testfile $testfilepathSp = Join-Path -Path $testpath -ChildPath $testfileSp Context "File removal Tests" { BeforeEach { From e3ee2920d576709b02492c72c9986b38a9270562 Mon Sep 17 00:00:00 2001 From: Ilya Date: Mon, 1 Apr 2019 19:34:59 +0800 Subject: [PATCH 05/10] Suppress New-Item output in test Co-Authored-By: kwkam --- .../Microsoft.PowerShell.Management/New-Item.Tests.ps1 | 8 ++++---- .../Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index 0d4f1792edf..9b187bb3a8b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -105,14 +105,14 @@ Describe "New-Item" -Tags "CI" { } It "Should create a file with correct name when Name switch is not used and Path contains special char" { - New-Item -Path $FullyQualifiedFileSp -ItemType file + New-Item -Path $FullyQualifiedFileSp -ItemType file > $null $FullyQualifiedFileSp | Should -Exist } It "Should be able to create a multiple items in different directories" { $FullyQualifiedFile2 = Join-Path -Path $tmpDirectory -ChildPath test2.txt - New-Item -ItemType file -Path $FullyQualifiedFile, $FullyQualifiedFile2 + New-Item -ItemType file -Path $FullyQualifiedFile, $FullyQualifiedFile2 > $null Test-Path $FullyQualifiedFile | Should -BeTrue Test-Path $FullyQualifiedFile2 | Should -BeTrue @@ -263,10 +263,10 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { } It "Should create symbolic link with name contains special char" { - $null = New-Item -Path $tmpDirectory -Name $testlinkSrcSpName -ItemType File + New-Item -Path $tmpDirectory -Name $testlinkSrcSpName -ItemType File > $null $FullyQualifiedLSrcSp | Should -Exist - $null = New-Item -Path $FullyQualifiedLinkSp -Target $FullyQualifiedLSrcSp -ItemType SymbolicLink + New-Item -Path $FullyQualifiedLinkSp -Target $FullyQualifiedLSrcSp -ItemType SymbolicLink > $null $FullyQualifiedLinkSp | Should -Exist $expectedTarget = Join-Path -Path $tmpDirectory -ChildPath $testlinkSrcSpName diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 index b7a0a6bf6ff..7793c95f03c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Remove-Item.Tests.ps1 @@ -114,10 +114,10 @@ Describe "Remove-Item" -Tags "CI" { } It "Should be able to remove file when path contains special char" { - New-Item -Path $testpath -Name $testfileSpName -ItemType File -Force + New-Item -Path $testpath -Name $testfileSpName -ItemType File -Force > $null $testfilepathSp | Should -Exist - Remove-Item -Path $testfilepathSp + Remove-Item -Path $testfilepathSp -Force $testfilepathSp | Should -Not -Exist } } From 582f67d627965984715a5b3fc51978859629aec1 Mon Sep 17 00:00:00 2001 From: kwkam Date: Sun, 5 May 2019 17:00:38 +0800 Subject: [PATCH 06/10] Use BeExactly instead of Match in test --- .../Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index 9b187bb3a8b..1bb4bd15d3a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -272,7 +272,7 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { $expectedTarget = Join-Path -Path $tmpDirectory -ChildPath $testlinkSrcSpName $fileInfo = Get-ChildItem -Path $FullyQualifiedLinkSp - $fileInfo.Target | Should -Match ([regex]::Escape($expectedTarget)) + $fileInfo.Target | Should -BeExactly $expectedTarget $fileInfo.LinkType | Should -BeExactly "SymbolicLink" $fileInfo.Attributes -band $DirLinkMask | Should -BeExactly $SymLinkMask } From 84a23edac48590ef79ae7a54c04b9840c300c982 Mon Sep 17 00:00:00 2001 From: kwkam Date: Sun, 5 May 2019 18:29:57 +0800 Subject: [PATCH 07/10] Use Get-Item instead of Get-ChildItem --- .../Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index 1bb4bd15d3a..1a20f478252 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -271,7 +271,7 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { $expectedTarget = Join-Path -Path $tmpDirectory -ChildPath $testlinkSrcSpName - $fileInfo = Get-ChildItem -Path $FullyQualifiedLinkSp + $fileInfo = Get-Item -Path $FullyQualifiedLinkSp $fileInfo.Target | Should -BeExactly $expectedTarget $fileInfo.LinkType | Should -BeExactly "SymbolicLink" $fileInfo.Attributes -band $DirLinkMask | Should -BeExactly $SymLinkMask From 581dd2a278e69d5e24f9f0f0d992d7d69c2a6484 Mon Sep 17 00:00:00 2001 From: kwkam Date: Wed, 8 May 2019 00:02:23 +0800 Subject: [PATCH 08/10] Fix symlink target --- .../engine/SessionStateContainer.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index e8a002a54cb..ae18bcff18e 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -3535,9 +3535,13 @@ internal void NewItem( throw PSTraceSource.NewInvalidOperationException(SessionStateStrings.PathNotFound, targetPath); } - // If the original target was a relative path, we want to leave it as relative if it did not require - // globbing to resolve. - if (WildcardPattern.ContainsWildcardCharacters(targetPath)) + // If the original target was a relative path, we want to leave it as relative + if (targetPath.StartsWith(".", StringComparison.OrdinalIgnoreCase)) + { + var SessionStateInt = ExecutionContext.EngineSessionState; + content = SessionStateInt.NormalizeRelativePath(globbedTarget[0], SessionStateInt.CurrentLocation.ProviderPath); + } + else { content = globbedTarget[0]; } From bf08aad27e8296d231aef78e11df854f6226e3af Mon Sep 17 00:00:00 2001 From: kwkam Date: Wed, 8 May 2019 20:02:52 +0800 Subject: [PATCH 09/10] Prepend dot to relative path --- .../engine/SessionStateContainer.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index ae18bcff18e..1db4794ae40 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -3536,10 +3536,11 @@ internal void NewItem( } // If the original target was a relative path, we want to leave it as relative - if (targetPath.StartsWith(".", StringComparison.OrdinalIgnoreCase)) + if (targetPath.StartsWith(".")) { - var SessionStateInt = ExecutionContext.EngineSessionState; - content = SessionStateInt.NormalizeRelativePath(globbedTarget[0], SessionStateInt.CurrentLocation.ProviderPath); + var sessionState = ExecutionContext.EngineSessionState; + string resolvedPath = sessionState.NormalizeRelativePath(globbedTarget[0], sessionState.CurrentLocation.ProviderPath); + content = resolvedPath.StartsWith(".") ? resolvedPath : Path.Combine(".", resolvedPath); } else { From 258e2cd57f56ed2bbf0d2ab92182b4cadbb37c2d Mon Sep 17 00:00:00 2001 From: kwkam Date: Wed, 8 May 2019 23:38:49 +0800 Subject: [PATCH 10/10] Use char in StartsWith --- .../engine/SessionStateContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index 1db4794ae40..1a9f7988678 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -3536,11 +3536,11 @@ internal void NewItem( } // If the original target was a relative path, we want to leave it as relative - if (targetPath.StartsWith(".")) + if (targetPath.StartsWith('.')) { var sessionState = ExecutionContext.EngineSessionState; string resolvedPath = sessionState.NormalizeRelativePath(globbedTarget[0], sessionState.CurrentLocation.ProviderPath); - content = resolvedPath.StartsWith(".") ? resolvedPath : Path.Combine(".", resolvedPath); + content = resolvedPath.StartsWith('.') ? resolvedPath : Path.Combine(".", resolvedPath); } else {