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

时间:2017-09-19 19:04:25

标签: powershell

我正在递归深层文件夹结构,以便像这样检索所有文件夹路径:

$subFolders = Get-ChildItem $rootFolder -Recurse -Directory  -ErrorVariable folderErrors | Select-Object -ExpandProperty FullName

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

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

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

new-psdrive -Name "long1" -PSProvider FileSystem -Root $folderErrors[0].CategoryInfo.TargetName

但是,在创建新的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

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

由于

1 个答案:

答案 0 :(得分:27)

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

要求是:

  • Windows Management Framework 5.1

  • .Net Framework 4.6.2或更新的

  • Windows 10 / Windows server 2016(Build 1607或更新版本)

可以使用以下代码段启用此政策。

#GPEdit location:  Configuration>Administrative Templates>System>FileSystem 
Set-ItemProperty 'HKLM:\System\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -value 1

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

虽然有一个问题。 这项工作仅限于 Powershell 5.1

从那里开始,不是以标准方式打电话:

get-childitem -Path 'C:\Very long path' -Recurse  

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

实施例

get-childitem -LiteralPath '\\?\C:\Very long path' -Recurse 

对于UNC路径,这略有不同,前缀为\\?\UNC\而不是\\

get-childitem -LiteralPath '\\?\UNC\127.0.0.1\c$\Very long path\' -Recurse

重要

调用Get-ChildItem unicode版本时,您应使用-LiteralPath参数代替Path

来自Microsoft文档

-LiteralPath

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

source

示例

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

输出 Get-Childitem with long paths

这是我为创建非常长的存储库而进行的实际功能测试,查询它以生成上面的输出并确认我可以创建超过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

值得一提

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

我还看到AlphaFS被提及了几次,这是一个允许克服260个字符限制的库。它是在Github上开源的,甚至还有一个(我没有测试过它)Get-AlphaFSChildItem建立在它上面的Technet here

其他参考

Long Paths in .Net

Naming Files, Paths, and Namespaces