By default it seems PowerShell uses the ANSI versions of FindFirstFile and FindNextFile, and is therefore limited to MAX_PATH - 260 characters in total. This PowerShell script uses in-line compiled VB.Net to call the wide unicode versions - FindFirstFileW and FindNextFileW - to bypass the ANSI MAX_PATH limitations. The results are essentially the same as a 'dir /s/b/a-d' that won't return with 'The filename or extension is too long.' or 'The directory name x is too long' errors.
If you use '/l', the script will only return deep paths, and also provide the 8.3 equivalent to the deep path - a useful method to access these files. For example, using this method, you can access a file with UNC (eg \\server\share) over 18 levels deep ((260-16)/13).
Note that these wide calls only bypass MAX_PATH when using a mapped drive with the \\?\ prefix to disable path parsing. Just specify a mapped drive or local path normally, eg c:\temp, the script will automatically prepend \\?\
I've been experimenting with using PowerShell to dynamically compile VB.Net or C# code, and within that managed code, calling unmanaged platform invoke operations to get to APIs. I like the flexibility of using a scripting language rather than compiled code, and while this certainly isn't as functional as 'dir', it was useful to me when at least trying to get a list of deep files.
## FindFiles.ps1 ##
[string] $dirRoot = $pwd,
[string] $Spec = "*.*",
[bool] $longOnly = $false
# 23/05/2008, Wayne Martin, Added the option to only report +max_path entries, and report the short path of those directories (which makes it easier to access them)
# Use the wide unicode versions to report a directory listing of all files, including those that exceed the MAX_PATH ANSI limitations
# Assumptions, this script works on the assumption that:
# There's a console to write the output from the compiled VB.Net
# Wayne Martin, 15/05/2008
# PowerShell . .\FindFiles.ps1 -d c:\temp -s *.*
# PowerShell . .\FindFiles.ps1 -d c:\temp
# PowerShell . .\FindFiles.ps1 -d g: -l $true
$provider = new-object Microsoft.VisualBasic.VBCodeProvider
$params = new-object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
$txtCode = @'
Const ERROR_SUCCESS As Long = 0
Private Const MAX_PREFERRED_LENGTH As Long = -1
Wayne's World of IT (WWoIT), Copyright 2008 Wayne Martin.