问题描述
我正在递归一个深层文件夹结构,以便像这样检索所有文件夹路径:
$subFolders = Get-ChildItem $rootFolder -Recurse -Directory -ErrorVariable folderErrors |选择对象 -ExpandProperty 全名
注意:在我的情况下,$rootFolder 是网络共享.即\\server\DeptDir$\somefolder"
$folderErrors
变量正确捕获了所有 FileTooLong 异常,因此我想使用长路径创建新的 PSDrive,以便递归这些长路径.
所以我使用这个 cmdlet 创建了一个新的 PSDrive:
new-psdrive -Name "long1" -PSProvider FileSystem -Root $folderErrors[0].CategoryInfo.TargetName
但是,在创建新的 PSDrive 后,我仍然收到 PathTooLong 异常.
PS C:\>>cd long1:PS long1:\>>目录dir : 指定的路径、文件名或两者都太长.完全限定的文件名必须少于 260 个字符,目录名必须少于 248 个字符.在行:1 字符:1+ 目录+~~~+ CategoryInfo : ReadError: (\\svr01\Dep...\Fibrebond ECO\:String) [Get-ChildItem], PathTooLongException+ FullQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand
我认为没有其他办法可以解决这个问题.我做错了什么吗?为什么我在路径太长的位置创建驱动器时,新的PSDrive会抛出PathTooLong?
谢谢
自 Windows 周年更新后,现在有一个本地策略可用.
要求是:
Windows 管理框架 5.1
.Net Framework 4.6.2 或更新版本
Windows 10/Windows Server 2016(内部版本 1607 或更新版本)
可以使用以下代码段启用此策略.
#GPEdit 位置:配置>管理模板>系统>文件系统Set-ItemProperty 'HKLM:\System\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -value 1
否则,您实际上可以通过调用 unicode 版本的 Windows API 来访问长度超过 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
来自微软文档
-LiteralPath
指定一个或多个位置的路径.与 -Path 参数不同,-LiteralPath 参数的值与键入的值完全相同.没有字符被解释为通配符.如果路径包含转义字符,请将它们括在单引号中.单引号告诉 Windows PowerShell 不要将任何字符解释为转义序列.
这是我为创建非常长的存储库而进行的实际功能测试,查询它以生成上面的输出并确认我可以创建超过 260 个字符的存储库并查看它们.
函数 CreateVeryLongPath([String]$Root,[Switch]$IsUNC,$FolderName = 'Dummy Folder',$iterations = 200) {$Base = '\\?\'if ($IsUNC) {$Base = '\\?\UNC\'}$CurrentPath = $Base + $Root + $FolderName + '\'对于 ($i=0;$i -le $iterations;$i++) {New-Item -Path $CurrentPath -Force -ItemType 目录 |出空$currentPath = $CurrentPath + $FolderName + '\'}}函数 QueryVeryLongPath([String]$Root,[Switch]$IsUNC) {$Base = '\\?\'if ($IsUNC) {$Base = '\\?\UNC\';$Root = $Root.substring(2,$Root.Length -2)}$BasePath = $Base + $RootGet-ChildItem -LiteralPath $BasePath -Recurse |ft @{'n'='Length';'e'={$_.FullName.Length}},FullName}CreateVeryLongPath -Root 'C:\__tmp\' -FolderName '这是一个文件夹'QueryVeryLongPath -Root 'C:\__tmp\Dummy Folder11\'#UNC - 在 UNC 共享路径上测试CreateVeryLongPath -Root '\\ServerName\ShareName\' -FolderName '这是一个文件夹' -IsUNCQueryVeryLongPath -Root '\\ServerName\ShareName\' -IsUNC
值得一提
在我的研究中,我看到有人提到使用 RoboCopy 然后解析其输出.我不是特别喜欢这种方法,所以我不会详细说明.(多年后,我发现 Robocopy 是 Windows 的一部分,而不是某些第三方实用程序.我想这也是一个不错的方法,尽管我更喜欢纯 Powershell 解决方案)
我还看到多次提到 AlphaFS,这是一个可以克服 260字数也有限制.它在 Github 上是开源的,甚至在 Technet
其他参考资料
I am recursing a deep folder structure in order to retreive all folder paths like so:
$subFolders = Get-ChildItem $rootFolder -Recurse -Directory -ErrorVariable folderErrors | Select-Object -ExpandProperty FullName
NOTE: $rootFolder in my case is a network share. i.e. "\\server\DeptDir$\somefolder"
The $folderErrors
variable is correctly capturing all the FileTooLong exceptions so I want to create new PSDrives using the long Paths in order to recurse those long paths.
So I create a new PSDrive using this cmdlet:
new-psdrive -Name "long1" -PSProvider FileSystem -Root $folderErrors[0].CategoryInfo.TargetName
However, after creating a new PSDrive I am still getting 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
I see no other way around this problem. Am I doing something incorrectly? Why is the new PSDrive throwing PathTooLong when I am creating a drive at the location where the path is too long?
Thanks
There is a local policy that is now available since Windows anniversary update.
Requirements are :
Windows Management Framework 5.1
.Net Framework 4.6.2 or more recent
Windows 10 / Windows server 2016 (Build 1607 or newer)
This policy can be enabled using the following snippet.
#GPEdit location: Configuration>Administrative Templates>System>FileSystem
Set-ItemProperty 'HKLM:\System\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -value 1
Otherwise, you can actually get to the paths longer than 260 characters by making your call to the unicode version of Windows API.
There's a catch though.This work only in Powershell 5.1 minimum.
From there, instead of making your call the standard way:
get-childitem -Path 'C:\Very long path' -Recurse
You will need to use the following prefix:\\?\
Example
get-childitem -LiteralPath '\\?\C:\Very long path' -Recurse
For UNC path, this is slightly different, the prefix being \\?\UNC\
instead of \\
get-childitem -LiteralPath '\\?\UNC\127.0.0.1\c$\Very long path\' -Recurse
Important
When calling Get-ChildItem
unicode version, you should use the -LiteralPath
parameter instead of Path
From Microsoft documentation
-LiteralPath
Specifies a path to one or more locations. Unlike the -Path parameter, the value of the -LiteralPath parameter is used exactly as it is typed. No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any characters as escape sequences.
Example
(get-childitem -LiteralPath '\\?\UNC\127.0.0.1\This is a folder$' -Recurse) |
ft @{'n'='Path length';'e'={$_.FullName.length}}, FullName
output
Here is the actual functional test I made to create the very long repository, query it to produce the output above and confirm I could create repository with more than 260 characters and view them.
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
Worth to mention
During my research, I saw people mentioning using RoboCopy then parse its output. I am not particularly fond of this approach so I won't elaborate on it.(edit: Years later, I discovered that Robocopy is part of Windows and not some third-party utility. I guess that would be an ok approach too, although I prefer a pure Powershell solution)
I also saw AlphaFS being mentionned a couple of time which is a library that allows to overcome the 260 characters limitation too. It is open sourced on Github and there's even a (I did not test it though) Get-AlphaFSChildItem
built on it available on Technet here
Other references
Naming Files, Paths, and Namespaces
这篇关于使用 New-PSDrive 处理路径太长异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!