See this all the time. Then when paths are too long they map a drive to a 
folder within the share and now the path is shorter for them. Sucks for the 
admin when trying to recover stuff!

Sent from my iPhone

> On Jan 8, 2016, at 8:05 AM, Melvin Backus <[email protected]> wrote:
> 
> I've always assumed that this happens via one of two scenarios.  I don't 
> believe I've ever validated this so maybe this is a good opportunity for 
> feedback from the group.
> 
> 1. They map a drive to a share on the server and then create a file which is 
> perfectly valid on their system, but the server path is longer.
> 
> 2. A folder/tree gets moved to somewhere else and the subtree results in 
> paths which exceed the limit.
> 
> --
> There are 10 kinds of people in the world...
>         those who understand binary and those who don't.
> 
> -----Original Message-----
> From: [email protected] [mailto:[email protected]] 
> On Behalf Of Kurt Buff
> Sent: Thursday, January 7, 2016 11:47 PM
> To: [email protected]
> Subject: Re: [powershell] Long file names - again...
> 
> I have no freaking idea how they do it. They're users, FFS, and who knows 
> what goes through their pea brains. I have yet to catch them in the act.
> 
> At any rate, thanks for this. I'll give it a whirl, and see if it works for 
> me - as noted, I've got somewhere north of 10m files.
> 
> BTW - I tried AlphaFS, and failed miserably with it - couldn't even get it to 
> do a directory listing - and then found in the wiki for it that it doesn't 
> support file hashing - it's on the feature request list.
> 
> There's another module called Zeta Long Paths, but it also says it has 
> limited functionality, so I hold out no hope for it.
> 
> I've looked at .NET CORE, and yes, it's not for the typical ignorant sysadmin 
> like me.
> 
> As an aside, I'm using powershell and vbscript already to generate a list of 
> all file names on the server, and then to output file/directory names longer 
> than 250 characters, and pestering users to shorten them, and in some cases 
> to flatten the directory structures. That's (as expected) a very long process.
> 
> Kurt
> 
>> On Thu, Jan 7, 2016 at 5:23 PM, Michael B. Smith <[email protected]> 
>> wrote:
>> How in the heck did you create filenames longer than MAX_PATH? I've tried 
>> everything I can think of, short of writing a C++ program that directly 
>> connects to the NTFS FS.
>> 
>> Anyway, this does much of what you want, with that exception. It takes a 
>> LONG time for large numbers of files. That is, a million or more.
>> 
>> [ CmdletBinding() ]
>> 
>> Param(
>>        [string] $item = 'C:\'
>> )
>> 
>> function timer
>> {
>>        ( Get-Date ).ToLongTimeString() }
>> 
>> function wv
>> {
>>        Param(
>>                [string] $str
>>        )
>> 
>>        Write-Verbose "$( timer ) $str"
>> }
>> 
>> ## we only need to create this once
>> $md5 = New-Object 
>> System.Security.Cryptography.MD5CryptoServiceProvider
>> 
>> function GetMyHash
>> {
>>        Param(
>>                [object] $fileObject
>>        )
>> 
>>        $function = 'GetMyHash:'
>> 
>>        wv "$function begin, fileobject name '$( $fileObject.FullName )'"
>> 
>>        if( $fileObject.NameLength -ge 256 )
>>        {
>>                ## here you should write a helper function!!!
>>                Write-Error "$function, filename too long '$( 
>> $fileObject.FullName )'"
>>        }
>>        else
>>        {
>>                # you can compress this to a single line, but if you do that, 
>> you
>>                # can't clean up resources. if you are doing hundreds of 
>> thousands
>>                # or millions of files -- you gotta clean up
>> 
>>                # $md5 is declared at the script level
>> 
>>                try
>>                {
>>                        [System.IO.FileStream] $file = 
>> [System.IO.File]::Open( $fileObject.FullName, 'Open', 'Read' )
>>                        $fileObject.Hash = [BitConverter]::ToString( 
>> $md5.ComputeHash( $file ) )
>> 
>>                        $file.Close()
>>                        $file.Dispose()
>>                        $file = $null
>>                }
>>                catch
>>                {
>>                }
>> 
>>                # $md5.Clear() --- don't do this
>>        }
>> 
>>        wv "$function exit"
>> }
>> 
>> function GetFileList
>> {
>>        Param(
>>                [string] $item
>>        )
>> 
>>        $function = 'GetFileList:'
>> 
>>        wv "$function begin, item '$item'"
>> 
>>        $params = New-Object System.Collections.Arraylist
>>        $params.AddRange( @(
>>                '/L',
>>                '/S',           # include subdirectories, but not empty ones
>>                '/NJH',         # no job header (no logo)
>>                '/BYTES',       # show filesizes in bytes
>>                '/FP',          # include full filename of file in path output
>>                '/NC',          # don't log file classes
>>                '/NDL',         # don't log directory names
>>                '/TS',          # include source filename timestamps
>>                '/XJ',          # exclude junction points
>>                '/R:0',         # number of retries on failed I/O
>>                '/W:0' ) )      # how long to wait between retries
>> 
>>        $countPattern = '^\s{3}Files\s:\s+(?<Count>\d+).*'
>>        $sizePattern  = '^\s{3}Bytes\s:\s+(?<Size>\d+(?:\.?\d+)\s[a-z]?).*'
>> 
>>        wv "$function initiating robocopy"
>>        $roboResults  = robocopy.exe $item Nothing $params
>>        wv "$function robocopy complete"
>>        wv "$function result from robocopy has $( $roboResults.Count ) 
>> results"
>> 
>>        [int] $count = 0
>>        foreach( $result in $roboResults )
>>        {
>>                $count++
>>                if( ( $count % 1000 ) -eq 0 )
>>                {
>>                        wv "$function count $count of $( $roboResults.Count )"
>>                }
>> 
>>                if( $result -match 
>> '(?<Size>\d+)\s(?<Date>\S+\s\S+)\s+(?<FullName>.*)' )
>>                {
>>                        try
>>                        {
>>                                New-Object PSObject -Property @{
>>                                        FullName   = $matches.FullName
>>                                        NameLength = $matches.FullName.Length
>>                                        Size       = $matches.Size
>>                                        Date       = [Datetime]$matches.Date
>>                                        Hash       = ''
>>                                }
>>                        }
>>                        catch
>>                        {
>>                                wv "fault: line     = '$result'"
>>                                wv "fault: fullname = '$( $matches.FullName 
>> )'"
>>                                wv "fault: namelen  = '$( 
>> $matches.FullName.Length )'"
>>                                wv "fault: size     = '$( 
>> $matches.Size.ToString() )'"
>>                                wv "fault: date     = '$( $matches.Date )'"
>>                        }
>>                }
>>                else
>>                {
>>                        wv "$function nomatch: $result $( if( $result ) { 
>> $result.Length } else { 'null' } )"
>>                }
>>        }
>> 
>>        wv "$function exit, count = $count"
>> }
>> 
>>        ##
>>        ## Main
>>        ##
>> 
>>        $global:fsiresult = GetFileList $item
>> 
>>        wv "Gonna calculate hashes"
>> 
>>        $global:fsiresult |% { GetMyHash $_ }
>> 
>>        wv "Done"
>> 
>> -----Original Message-----
>> From: [email protected] 
>> [mailto:[email protected]] On Behalf Of Kurt Buff
>> Sent: Wednesday, December 30, 2015 5:20 PM
>> To: [email protected]
>> Subject: Re: [powershell] Long file names - again...
>> 
>> Ultimate goal is still the same - I want to get fullname, length and a hash 
>> of each file (md5 or sha1, for duplicate detection only), so AFAICT 
>> PowerShell is still the way to go.
>> 
>> Unless I can use md5sum from unxtools or gnuwin32 toolsets, or something 
>> like that.
>> 
>> Not worried about junctions at this point. I probably should look at 
>> New-PsDrive for grins.
>> 
>> I'll also take a look at .NET CORE - though I doubt I can take advantage of 
>> it if it hasn't been made easily available to powershell.
>> 
>> Kurt
>> 
>>> On Wed, Dec 30, 2015 at 1:47 PM, Michael B. Smith <[email protected]> 
>>> wrote:
>>> Actually, in this case, I think it's the .NET MAX_PATH (260).
>>> 
>>> .NET itself, in its PathHelper class,  doesn't accept the '\\?\' syntax and 
>>> explicitly throws an exception if the path exceeds 259 (ANSI) or 129 
>>> (Unicode). This class is used all over .NET.
>>> 
>>> Now, .NET CORE has been enhanced to support long paths.  But that isn't 
>>> today... for most people.
>>> 
>>> There are a few libraries (third party) you can use to add this support to 
>>> PowerShell. They basically wrap the low-level APIs using P/Invoke (which 
>>> you can do yourself, with Add-Type). They are much lower impact than 
>>> installing Cygwin, but still... I guess my question is this: what are you 
>>> really trying to do?
>>> 
>>> Cmd.exe and the subst command are still my "go to solution" for long paths. 
>>> You can also fake this in PowerShell with New-PsDrive (or "net share...") 
>>> if you absolutely must stay in PowerShell, but it gets a little nasty if 
>>> you need to worry about junctions.
>>> 
>>> -----Original Message-----
>>> From: [email protected]
>>> [mailto:[email protected]] On Behalf Of Kurt Buff
>>> Sent: Wednesday, December 30, 2015 4:13 PM
>>> To: [email protected]
>>> Subject: [powershell] Long file names - again...
>>> 
>>> All,
>>> 
>>> If anyone can help, I'd much appreciate it.
>>> 
>>> I'm picking up where I left off some time ago in auditing our file server.
>>> 
>>> I used robocopy to generate a list of files for each drive on our file 
>>> server - all told over 10.3m lines, massaged the output (with findstr) to 
>>> break it up by drive letter and to remove directories and things like 
>>> $recycle.bin and 'system volume', then further massaged the output to 
>>> remove the extraneous robocopy markings. I had to break it into smaller 
>>> files by partition because processing the file in powershell overran RAM on 
>>> a 16g machine.
>>> 
>>> I then took each line (which looked like, e.g.
>>> i:\somedirectory\otherdirectory\file), then prepended '\\?\' to each 
>>> line), because some number of the files have path lengths greater 
>>> than
>>> 260 characters, and I'm hoping that using this specification will allow 
>>> access to those files without adding funky 3rd party tools.
>>> 
>>> So, I've ended up with a set of text files that have many lines that look 
>>> like this:
>>>     \\?\i:\somedirectory\otherdirectory\file
>>> 
>>> What I'm trying to do is illustrated by the following, but I'm getting no 
>>> output from it - it just returns without any output after a few moments.
>>> 
>>>     $files = get-content c:\batchfiles\file-i.txt
>>>     foreach ( $file in $files )
>>>     {
>>>        get-childitem $file | select length, fullname
>>>     }
>>> 
>>> 
>>> However, if I strip the '\\?\' from each line, it does what I want - but of 
>>> course the script fails as soon as it encounters a file that has a 
>>> name/directory specification that exceeds the Win32 API limit.
>>> 
>>> I've tried surrounding the string with both double and single quotes, and 
>>> still no joy.
>>> 
>>> A simpler example tells the tale:
>>> 
>>> This works, except for long file names:
>>>     gci i:\somedirectory\otherdirectory\file
>>> 
>>> These fail silently:
>>>     gci \\?\i:\somedirectory\otherdirectory\file
>>>     gci "\\?\i:\somedirectory\otherdirectory\file"
>>>     gci '\\?\i:\somedirectory\otherdirectory\file'
>>> 
>>> These fail with an error:
>>>     gci "\\\\?\\i:\somedirectory\otherdirectory\file"
>>>     gci '\\\\?\\i:\somedirectory\otherdirectory\file'
>>> 
>>> The error is:
>>> Get-ChildItem : Cannot retrieve the dynamic parameters for the cmdlet.
>>> Cannot process argument because the value of argument "path" is not valid. 
>>> Change the value of the "path" argument and run the operation again.
>>> At line:1 char:1
>>> + gci "\\\\?\\i:\CFRemoteImages\Air Canada Montreal STOC.vhd" | 
>>> + select
>>> length, ful ...
>>> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem],
>>> ParameterBindingException
>>>    + FullyQualifiedErrorId :
>>> GetDynamicParametersException,Microsoft.PowerShell.Commands.GetChildI
>>> t
>>> emCommand
>>> 
>>> 
>>> ================================================
>>> Did you know you can also post and find answers on PowerShell in the forums?
>>> http://www.myitforum.com/forums/default.asp?catApp=1
>>> 
>>> 
>>> ================================================
>>> Did you know you can also post and find answers on PowerShell in the forums?
>>> http://www.myitforum.com/forums/default.asp?catApp=1
>> 
>> 
>> ================================================
>> Did you know you can also post and find answers on PowerShell in the forums?
>> http://www.myitforum.com/forums/default.asp?catApp=1
>> 
>> 
>> ================================================
>> Did you know you can also post and find answers on PowerShell in the forums?
>> http://www.myitforum.com/forums/default.asp?catApp=1
> 
> 
> ================================================
> Did you know you can also post and find answers on PowerShell in the forums?
> http://www.myitforum.com/forums/default.asp?catApp=1
> 
> 
> ================================================
> Did you know you can also post and find answers on PowerShell in the forums?
> http://www.myitforum.com/forums/default.asp?catApp=1


================================================
Did you know you can also post and find answers on PowerShell in the forums?
http://www.myitforum.com/forums/default.asp?catApp=1

Reply via email to