使用New-PSDrive处理路径过长的异常

Chi*_*ago 11 powershell

我正在递归一个深层文件夹结构,以便检索所有文件夹路径,如下所示:

$subFolders = Get-ChildItem $rootFolder -Recurse -Directory  -ErrorVariable folderErrors | Select-Object -ExpandProperty FullName
Run Code Online (Sandbox Code Playgroud)

注意:在我的情况下,$ rootFolder是一个网络共享.即"\\ server\DeptDir $\somefolder"

$folderErrors变量正确捕获所有FileTooLong异常,因此我想使用长路径创建新的PSDrives以递归这些长路径.

所以我使用这个cmdlet创建了一个新的PSDrive:

new-psdrive -Name "long1" -PSProvider FileSystem -Root $folderErrors[0].CategoryInfo.TargetName
Run Code Online (Sandbox Code Playgroud)

但是,在创建新的PSDrive之后,我仍然会收到PathTooLong Exceptions.

PS C:\>> cd long1:
PS long1:\>> dir
dir : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
At line:1 char:1
+ dir
+ ~~~
    + CategoryInfo          : ReadError: (\\svr01\Dep...\Fibrebond ECO\:String) [Get-ChildItem], PathTooLongException
    + FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand
Run Code Online (Sandbox Code Playgroud)

我认为这个问题别无他法.我做错了什么吗?当我在路径太长的位置创建驱动器时,为什么新的PSDrive会抛出PathTooLong?

谢谢

Sag*_*pre 31

自Windows周年更新后,现在可以使用本地策略.

要求是:

  • Windows Management Framework 5.1

  • .Net Framework 4.6.2或更新版本

  • Windows 10/Windows服务器2016(Build 1607或更高版本)

可以使用以下代码段启用此策略.

#GPEdit location:  Configuration>Administrative Templates>System>FileSystem 
Set-ItemProperty 'HKLM:\System\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -value 1
Run Code Online (Sandbox Code Playgroud)

否则,通过调用Windows API的unicode版本,您实际上可以访问超过260个字符的路径.

虽然有一个问题.这项工作仅限于Powershell 5.1最低要求.

从那里,而不是以标准的方式打电话:

get-childitem -Path 'C:\Very long path' -Recurse  
Run Code Online (Sandbox Code Playgroud)

您需要使用以下前缀: \\?\

get-childitem -LiteralPath '\\?\C:\Very long path' -Recurse 
Run Code Online (Sandbox Code Playgroud)

对于UNC路径,这略有不同,前缀\\?\UNC\代替\\

get-childitem -LiteralPath '\\?\UNC\127.0.0.1\c$\Very long path\' -Recurse
Run Code Online (Sandbox Code Playgroud)

重要

调用Get-ChildItemunicode版本时,应该使用-LiteralPath参数而不是Path

来自Microsoft文档

-LiteralPath

指定一个或多个位置的路径.与-Path参数不同,-LiteralPath参数的值与键入的值完全相同.没有字符被解释为通配符.如果路径包含转义字符,请将它们用单引号括起来.单引号告诉Windows PowerShell不要将任何字符解释为转义序列.

资源

(get-childitem -LiteralPath '\\?\UNC\127.0.0.1\This is a folder$' -Recurse) | 
ft @{'n'='Path length';'e'={$_.FullName.length}}, FullName 
Run Code Online (Sandbox Code Playgroud)

产量 Get-Childitem有很长的路径

这是我为创建非常长的存储库而进行的实际功能测试,查询它以生成上面的输出并确认我可以创建超过260个字符的存储库并查看它们.

Function CreateVeryLongPath([String]$Root,[Switch]$IsUNC,$FolderName = 'Dummy Folder',$iterations = 200) {
    $Base = '\\?\'
    if ($IsUNC) {$Base = '\\?\UNC\'}

    $CurrentPath = $Base + $Root + $FolderName + '\'

    For ($i=0;$i -le $iterations;$i++) {

    New-Item -Path $CurrentPath -Force -ItemType Directory | Out-Null
    $currentPath = $CurrentPath +  $FolderName + '\'
    }
}

Function QueryVeryLongPath([String]$Root,[Switch]$IsUNC) {
    $Base = '\\?\'
    if ($IsUNC) {$Base = '\\?\UNC\';$Root = $Root.substring(2,$Root.Length -2)}

    $BasePath = $Base + $Root
    Get-ChildItem -LiteralPath $BasePath -Recurse | ft @{'n'='Length';'e'={$_.FullName.Length}},FullName
}



CreateVeryLongPath -Root 'C:\__tmp\' -FolderName 'This is a folder'
QueryVeryLongPath -Root 'C:\__tmp\Dummy Folder11\' 

#UNC - tested on a UNC share path 
CreateVeryLongPath -Root '\\ServerName\ShareName\' -FolderName 'This is a folder' -IsUNC
QueryVeryLongPath -Root '\\ServerName\ShareName\' -IsUNC
Run Code Online (Sandbox Code Playgroud)

值得一提

在我的研究中,我看到人们提到使用RoboCopy然后解析它的输出.我不是特别喜欢这种方法,所以我不会详细说明.

我还看到AlphaFS提及了几次,这是一个允许克服260个字符限制的库.它是开源了Github上甚至还有一个(我没有,虽然测试)Get-AlphaFSChildItem建在它可用在Technet上这里

其他参考

.Net中的长路径

命名文件,路径和命名空间

  • 如果我三周前知道这一点,我会节省很多时间。相反,我映射驱动器、操作字符串、尝试解析 robocopy 输出,并且通常浪费了大量时间。卫生部! (3认同)