Search code examples
powershellget-childitem

PowerShell "get-childitem2" size over ~3.5gb


This link points to Get-Childitem2, a function which allows traversing the 260 character limit.

https://gallery.technet.microsoft.com/scriptcenter/Get-ChildItemV2-to-list-29291aae#content.

It's a great function which works really well, however, it misreports file sizes over ~3.5GB which is the whole reason I'm running it. I'm at pains to admit I'm just not good enough to find and fix the code so it accurately reports file sizes over ~3.5GB.

I imagine it's somewhere here; as there doesn't appear to be an 'nFileSizeHigh' option:

                    } Else {
                    $Object.Length = [int64]("0x{0:x}" -f $findData.nFileSizeLow)
                    $Object.pstypenames.insert(0,'System.Io.FileInfo')
                }

I've chosen this over Robocopy and AlphaFS as I've had various issues with both. Example of file size issues:

get-childitem C:\Temp\Huge: (correct size in bytes)

3166720000 - sp1_vl_build_x64_dvd_617403.iso
5653628928 - server_2016_x64_dvd_9327751.iso
4548247552 - it_English_-3_MLF_X19-53588.ISO

get-childitem2 C:\Temp\Huge:

3166720000 - sp1_vl_build_x64_dvd_617403.iso
1358661632 - server_2016_x64_dvd_9327751.iso
253280256 - it_English_-3_MLF_X19-53588.ISO


Solution

  • From this documentation

    The size of the file is equal to (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow

    And at the top of the script (line 92) is a mention of nFileSizeHigh, but no attempt to add it into the file length. So I can only guess the script is buggy and wasn't tested on files larger than [DWORD MAX] which is [uint32]::MaxValue, or about 3.5GB.

    If you change the two lines up at the top to [uint32] instead of [int32]:

            [void]$STRUCT_TypeBuilder.DefineField('nFileSizeHigh', [uint32], 'Public')
            [void]$STRUCT_TypeBuilder.DefineField('nFileSizeLow', [uint32], 'Public')
    

    and make the length calculation more like the documentation link:

    $Object.Length = ($findData.nFileSizeHigh * ([uint32]::MaxValue+1)) + ([int64]('0x{0:x}' -f $findData.nFileSizeLow))
    

    then it handles a file of ~7GB correctly in my quick testing.

    Why it's going through string formatting to convert to int64, and how it should be done properly, I don't know, this is mostly trial and error until it worked.