'Does (get-item $file).GetHashCode() calculate the hash on the fly like get-filehash or used a pre-computed hash?

We're working on a PowerShell script for forensic baseline analysis which recursively iterates over the file-system recording a hierarchy of directories and files, with the filenames mapped to hashes and dump that data to JSON. Since we're interested in doing this for every file on the system, it needs to be as fast as it can be.

The ideal output for a small test directory is like:

{
    "\\3D Objects":  {

                     },
    "\\Contacts":  {

                   },
    "\\Desktop":  {
                      "\\that":  {
                                     "\\somedoc":  "@{textdoc.txt=C700784FAD1A992A90D71CBC1ADB0F22BF286AD6FE4C9BF42A0407BAF8F3D068}",
                                     "bruh.txt":  "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
                                     "eula.lnk":  "FD068EACB3CC0C1ED2F246542426680F255614791BCD4E0EC615A4B1CEF1F0FA"
                                 },
                      "\\this":  {
                                     "\\another folder":  "@{\\kelp=; thebesometext.txt=BE47BDE1B74F38E47064C1185A1AC8261C9EEEBE9D32ACF25047F5BC4EB5BC8D}",
                                     "ok.txt":  "C5273884B90D490134E7737B29A65405CEA0F7BB786CA82C6337CEB24DE6F5ED",
                                     "sample.txt":  "766D6A6A2330070C98D2AD44C9A4345DB8C6E65BAECC82B6D2CF801126F98DF6"
                                 },
                      "192.168.176.131_Scraped_Files.zip":  "153891A4A3951D9D86C0DFC3F1D9B5FB7886EC754237B078C5657E271A8EC5FB",
                      "bruh.rar":  "BA9B9AD700B82029AEC0DAE52B06E4A09C60255D996DD5A40F7DED61D3DD2795",
                      "FileSystemtoJSON.ps1":  "2E8C2CDFD495DB137B7B46A7FDAC6040E51CD6464D5B9C84B67F179D2B7A9C2B",
                      "File_Scraper.ps1":  "7BFD3600894D39CEEB1BE921C24A3BCDB58C4CE1114D376DB908A95F2CF49FC1",
                      "FStoJson.ps1":  "FACF2C77FA004502C10066E8757D31B1A134878345965F60B80D5CC7CF2A2B44"
                  },
    "\\Documents":  {
                        "\\WindowsPowerShell":  {

                                                }
                    },
    "\\Downloads":  {
                        "winrar-x64-611.exe":  "24FC7955FADA6B9802F4E50E935EBD5654FD7382FAF641B27DD626F4B3563974"
                    },
    "\\Favorites":  {
                        "\\Links":  {

                                    },
                        "Bing.url":  "E0C0A5A360482B5C5DED8FAD5706C4C66F215F527851AD87B31380EF6060696E"
                    },
    "\\Links":  {
                    "Desktop.lnk":  "B559BF8483620D2C64B12901AAC7CAB21219F750E97FFC7FFC2808A7B5B9648D",
                    "Downloads.lnk":  "A0F8549CAB3926988971D8738CB9DE27964B6B47707674A3419DDCCA82935565"
                },
    "\\Music":  {

                },
    "\\OneDrive":  {

                   },
    "\\Pictures":  {
                       "\\Camera Roll":  {

                                         },
                       "\\Saved Pictures":  {

                                            }
                   },
    "\\Saved Games":  {

                      },
    "\\Searches":  {
                       "winrt--{S-1-5-21-321011808-3761883066-353627080-1000}-.searchconnector-ms":  "3B33937704E0EBEC50DD91E982DD4CADDC1ED0DB23864AB28A14A43910C393D0"
                   },
    "\\Videos":  {

                 }
}

Our original script was like this:

$root = [PSCustomObject]@{}

function FSSkimmer {
Param(
[Parameter(Mandatory=$True)][string]$path,
[Parameter(Mandatory=$True)][PsCustomObject]$currentobject)

$paths = gci $path | Select-Object -ExpandProperty Fullname
    foreach ($file in $paths) { 
        if (!$(get-item $file | Select-Object -ExpandProperty PSiscontainer)) {
            $name = get-item $file | Select-Object -ExpandProperty Name
            $hash = Get-FileHash $file -Algorithm SHA256 | Select-Object -ExpandProperty Hash
            $currentobject | Add-Member -MemberType NoteProperty -Name $name -Value $hash
        }
        else {
            $dir_name = get-item $file | Select-Object -ExpandProperty Name
            $dir = [PSCustomObject]@{}
            $currentobject | Add-Member -MemberType NoteProperty -Name "\$($dir_name)" -Value $(FSSkimmer -path $file -currentobject $dir)
        }
    }
return $currentobject
}

$null = FSSkimmer -path "C:\" -currentobject $root

ConvertTo-Json -InputObject $root

This is slow. Reducing the hashing algorithm from Sha-256 to something less computationally expensive does help the speed. But I noticed one alternative:

(get-item $file).GetHashCode()

Is there anything fundamentally different about this method to get-filehash? Is it using some pre-computed hash stored by windows? (I know file-explorer shows a hash when you pull the properties, but don't know if this hash is cached on every file write or calculated on the fly every time properties are open. I suspect for some reason this might be the same feature exposed in PS.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source