19

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

ChiliYago
  • 11,341
  • 23
  • 79
  • 126

1 Answers1

49

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 Get-Childitem with long paths

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

Sage Pourpre
  • 9,932
  • 3
  • 27
  • 39
  • This looks promising but no...not working.. nothing returned. I should have stated that this is a network share. So using your example in my case would look like:Get-ChildItem -Path "\\?\server\DeptDirs$\SomeFolder" -Recurse -Directory – ChiliYago Sep 19 '17 at 22:11
  • 1
    @ChiliYago Actually, for UNC, the prefix goes from \\?\ to \\?\UNC\YourServer . See the last example in my edit. – Sage Pourpre Sep 20 '17 at 01:18
  • I still get nothing. This is my attempt: Get-ChildItem "\\?\UNC\somesever\myshare$\folder1\folder2\folder3" -Recurse -Directory – ChiliYago Sep 20 '17 at 18:32
  • Do you have powershell 5 ? I noticed that it didn't work on PS4 machines. Also, I had the same issue as you when I tried a share instead of Drive$. To fix that, I used LiteralPath instead of Path. I updated my answer again. – Sage Pourpre Sep 20 '17 at 19:52
  • 1
    The machine I am running the script on is PS5 but that is very unlikely on the machines hosting the shared folder. My next attempt returns the error: Illegal characters in path. Get-ChildItem -LiteralPath "\\?\UNC\somesever\myshare$\folder1\folder2\folder3" -Recurse -Directory – ChiliYago Sep 20 '17 at 21:26
  • How did you populate your test folder? I see you are using a share on the same machine 127.0.0.1 as where you are running the script. – ChiliYago Sep 20 '17 at 22:01
  • @ChiliYago Actually, I said Powershell 5 but it appears it works only with Powershell 5.1 and forward. I had another test server which had Powershell 4 (did not work). I updated to Powershell 5 (did not work / gave illegal characters in path) then Powershell 5.1 ... It now works from that server too. – Sage Pourpre Sep 21 '17 at 01:23
  • I now included the actual test function I used to populate the folder, then view the result. See the end of my answer. For me, it worked from a Server 2012 R2 and a Win 10 machine . Server 2012 R2 I had to update to WMF / Powershell 5.1 for it to work. – Sage Pourpre Sep 21 '17 at 01:25
  • 1
    Added AlphaFS reference too, which i saw a couple of time, which might be of interest if using Powershell 5.1 still does not work. See Worth to mention section. – Sage Pourpre Sep 21 '17 at 01:37
  • Thanks for the help. I'll mark this as solved even regardless. – ChiliYago Sep 21 '17 at 13:31
  • 1
    For others like me looking for Powershell 5.1; install the Windows Management Framework (WMF) 5.1 which includes Powershell 5.1. It's important to select the correct install file. For Server 2012 R2 I had to choose Win8.1AndW2K12R2-KB3191564-x64.msu. Then the new prefixes for the Unicode Windows API worked for me! – SeanOB Nov 13 '17 at 01:18
  • Fantastic post! This also applies to other CmdLets like `Get-Acl -LiteralPath "\\?\$FullName"`, `Test-Path -LiteralPath "\\?\$FullName"` – DarkLite1 May 03 '18 at 09:49
  • Hmm, I can list long paths with no problem in ps 5.1.16299.611, without the \\?\ prefix. – js2010 Sep 07 '18 at 16:56
  • 3
    If I knew this 3 weeks ago, I would have saved myself SOOO much time. Instead, I mapped drives, manipulated strings, attempted parsing robocopy output, and generally wasted loads of time. DOH! – OutOfThisPlanet Sep 20 '18 at 15:26
  • 1
    I just updated my answer with a new solution available for windows build 1607 + (anniversary update) – Sage Pourpre Jan 10 '19 at 01:05
  • I tried using the \\?\ notation on Windows Server 2008 R2/ 2012 R2 and it doesn't work. Get-ChildItem : Illegal characters in path. I guess Powershell 5.1 AND Windows 10/2016 are required – theadzik Aug 06 '19 at 08:59