使用 New-PSDrive 处理路径太长异常 [英] Handling Path Too Long Exception with New-PSDrive

查看:47
本文介绍了使用 New-PSDrive 处理路径太长异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

$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 这里

其他参考资料

.Net 中的长路径

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

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.

source

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

Long Paths in .Net

Naming Files, Paths, and Namespaces

这篇关于使用 New-PSDrive 处理路径太长异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆