-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
Note: This is a generalization of #4439. @SteveL-MSFT, if you agree, please close the latter.
Prefixing full, normalized, native filesystem paths with \\?\ allows targeting filesystem items whose path is longer than the legacy limit of 259 characters.
Update:
- Prefix
\\?\isn't needed in PS Core (in .NET Core altogether), so long paths just work as-is, even if not enabled system-wide. - However, old code may still use it, and even new code may have to, when creating cross-edition scripts.
- Additionally, and separately,
\\?\is useful for targeting files or directories with irregular names, such as ones with trailing spaces, so you can remove them withRemove-Item, for instance.
As an aside: In Windows 10 you can now opt in system-wide to support long paths, but individual applications must also opt in (PowerShell indirectly does) - see https://blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/net-4-6-2-and-long-paths-on-windows-10/
As of PowerShell Core 7.3.0-preview.2, the inconsistent support for \\?\ is as follows:
-
With the
-Pathparameter,\\?\isn't supported at all , so wildcard expressions cannot be used.Get-ItemandGet-ChildItemoutput nothing, andRemove-Itemis a quiet no-op (silent failure) too.
-
With the
-LiteralPathparameter in combination with\\?\:- Only file paths can be targeted.
- Directory paths exhibit the following behavior:
Get-ItemandRemove-Itemcomplain about not finding the path.- Adding
-ForcemakesGet-Itemoutput a brokenDirectoryInfoinstance. - Using
Remove-Itemwithout-Recurseon a nonempty directory presents the usual confirmation prompt (implying the ability to recognize the path as existent), but then fails on confirmation.
- Adding
Get-ChildItemreports the root directory's content instead(!)
Additionally, \\?\ paths do not work in the following cases:
-
With
>/>>, which implicitly behave likeOut-File -Path- see Some scripts / files with wildcard metacharacter [ in the file name or path cannot be invoked or redirected to #4726 -
In the same vein, invocation of an executable - whether with or without(no longer a problem as of PowerShell Core 7.3.0-preview.2)&- is broken (possibly related to Some scripts / files with wildcard metacharacter [ in the file name or path cannot be invoked or redirected to #4726 as well). -
(no longer a problem as of PowerShell Core 7.3.0-preview.2)Start-Process -
Set-Location(not even with-LiteralPath)
Note:
-
Some of these problems are regressions from Windows PowerShell, where only the invocation /
Start-Processtests fail and>only with a new file. -
I haven't looked into whether invoking an executable with an overly long path is supported in principle by the underlying APIs.
Steps to reproduce
Run the following from a Pester test script (*.Tests.ps1) on Windows:
Describe "Support for long paths, via \\?\" {
BeforeAll {
Push-Location (Convert-Path TestDrive:\)
$dirPath = $PWD.ProviderPath
$PrefixedDir = "\\?\$dirPath"
$fileName = ('a' * 248 + '.cmd')
$fileNameAlt = ('b' * 248)
$PrefixedFullName = "$PrefixedDir\$fileName"
$PrefixedFullNameAlt = "$PrefixedDir\$fileNameAlt"
# Create the file with the overly long path using .NET,
# to avoid issues with New-Item
[IO.File]::WriteAllText($PrefixedFullName, '')
}
It "Get-ChildItem -LiteralPath" {
Get-ChildItem -LiteralPath $PrefixedFullName | % FullName | Should -Be $PrefixedFullName
}
It "Get-ChildItem -Path" {
Get-ChildItem -Path $PrefixedFullName | % FullName | Should -Be $PrefixedFullName
}
It "Remove-Item -LiteralPath" {
{ Remove-Item -LiteralPath $PrefixedFullName } | Should -Not -Throw
# Recreate the file.
[IO.File]::WriteAllText($PrefixedFullName, '')
}
It "Remove-Item -Path" {
{ Remove-Item -Path $PrefixedFullName } | Should -Not -Throw
# Recreate the file, if necessary
[IO.File]::WriteAllText($PrefixedFullName, '')
}
It "> with new file" {
{ '' > $PrefixedFullNameAlt } | Should -Not -Throw
}
It "> / >> with existing file." {
{ '@echo Hi.' > $PrefixedFullName } | Should -Not -Throw
{ 'REM ' >> $PrefixedFullName } | Should -Not -Throw
}
It "Invocation / &" {
& $PrefixedFullName | Should -Be 'Hi.'
}
It "Start-Process" {
Start-Process -FilePath $PrefixedFullName
}
It "New-Item" {
{ New-Item -Force -Type File $PrefixedFullName } | Should -Not -Throw
}
It "Set-Location -LiteralPath" {
{ Set-Location -EA Stop -LiteralPath $PrefixedDir } | Should -Not -Throw
}
It "Set-Location -Path" {
{ Set-Location -EA Stop -Path $PrefixedDir } | Should -Not -Throw
}
AfterAll {
# Use .NET to remove the overly long path, so that Pester itself doesn't
# fail on trying to remove the dir. underlying TestDrive:
[IO.File]::Delete($PrefixedFullName)
[IO.File]::Delete($PrefixedFullNameAlt)
Pop-Location
}
}Expected behavior
All tests should pass.
Actual behavior
All tests but the first one fail, with various error messages.
Environment data
PowerShell Core 7.0.0-preview.4