Skip to content

Instantly share code, notes, and snippets.

@GrantTrebbin
Created October 15, 2016 13:34
Show Gist options
  • Save GrantTrebbin/bacc9f1ea0376b58cac44729a57ace91 to your computer and use it in GitHub Desktop.
Save GrantTrebbin/bacc9f1ea0376b58cac44729a57ace91 to your computer and use it in GitHub Desktop.
Create fingerprints of directories and files that incorporate name and directory structure
function Hex_To_Bytes($hex){
# Takes a string with an even number of hexadecimal characters and
# converts it two characters at a time to an array of bytes half as long
# Initialize ouput byte array
$hexLength = $hex.Length
$byteLength = $hexLength / 2
$bytes = ,0 * ($byteLength)
# generate bytes by taking 2 hexadecimal characters at a time
for($i=0; $i -lt $byteLength; $i++){
$bytes[$i] = [System.Convert]::ToByte($hex.Substring($i*2,2),16)
}
return $bytes
}
function XOR_Hex($hex1, $hex2){
# Takes two strings of hexadecimal characters
# Find the length of the longest hex value
$l1 = $hex1.length
$length = $l1
$l2 = $hex2.length
if ($l2 -gt $length) {$length = $l2}
# Round that length up to the nearest even number
$length = 2 * [Math]::Ceiling($length/2)
# Make both hex strings this long by padding the left with zeros
$hex1 = $hex1.PadLeft($length, '0')
$hex2 = $hex2.PadLeft($length, '0')
# Convert these strings to byte arrays
$b1 = Hex_To_Bytes $hex1
$b2 = Hex_To_Bytes $hex2
# XOR the the byte arrays
$xored = ,0 * ($length/2)
for ($i = 0; $i -lt $b1.Count; $i++){
$xored[$i] = [char]($b1[$i] -bxor $b2[$i])
}
# Convert the byte array into a hex string
$hexstring = [System.BitConverter]::ToString($xored) -replace '-'
return $hexstring
}
function Byte_Hash([array]$bytesToHash) {
# Calculate the hash of a byte array
$hasher = new-object System.Security.Cryptography.MD5CryptoServiceProvider
$hashByteArray = $hasher.ComputeHash($bytesToHash)
# Convert the byte array to a hexadecimal string
foreach($byte in $hashByteArray)
{
$result += "{0:X2}" -f $byte
}
return $result;
}
function String_Hash([string]$textToHash) {
# Calculate the hash of a UTF8 byte representation of a String
$bytesToHash = [System.Text.Encoding]::UTF8.GetBytes($textToHash)
$result = Byte_Hash $bytesToHash
return $result;
}
function Hash_File($FilePath){
# Extract the file name from the path
$fileName = Split-Path -Path $FilePath.ToString() -Leaf
# Get the hash of the file and file name
$contentHash = (Get-FileHash $FilePath -Algorithm MD5).Hash
$nameHash = String_Hash $fileName
# Combine the two hashes with an XOR
$xorOfHashes = XOR_HEX $nameHash $contentHash
# Take the hash of the XOR result and return it
$byteXorOfHashes = Hex_To_Bytes $xorOfHashes
$hashOfXor = Byte_Hash $byteXorOfHashes
return $hashOfXor
}
function Hash_Directory($directoryPath){
# Get all the items in a directory
$items = Get-ChildItem -Path $directoryPath -Filter "" -Force| Select FullName
$contentHash = "00000000000000000000000000000000"
# Process each item
ForEach($item in $items){
# Get the attributes of each item
$itemName = (Get-Item -Force $item.FullName)
$Attributes = $itemName.Attributes.ToString()
$reparsePoint = $Attributes.Contains("ReparsePoint")
$directory = $Attributes.Contains("Directory")
$calculateHash = $true
# Include or exclude reparse point directories
if (($reparsePoint -eq $true) -and ($directory -eq $true)){
$calculateHash = $true
}
# Include or exclude reparse point files
if (($reparsePoint -eq $true) -and ($directory -eq $false)){
$calculateHash = $true
}
# Calculate the item hash and combine it with the total
if ($calculateHash -eq $true){
$itemHash = Get_Item_Hash $item.FullName
$contentHash = XOR_Hex $contentHash $itemHash
}
}
# Hash the name of the directory
$directoryName = Split-Path -Path $directoryPath.ToString() -Leaf
$nameHash = String_Hash $directoryName
# Combine the name and content hashes
$xorOfHashes = XOR_HEX $nameHash $contentHash
# Hash the combined hash
$byteXorOfHashes = Hex_To_Bytes $xorOfHashes
$hashOfXor = Byte_Hash $byteXorOfHashes
return $hashOfXor
}
function Get_Item_Hash($item){
# Find the object
$itemobject = Get-Item $item -Force
# Take the appropriate action if the object is a file or directory
$IsDirectory = $itemobject -is [System.IO.DirectoryInfo]
if($IsDirectory -eq $true){
$hashValue = Hash_Directory $item
}else{
$hashValue = Hash_File $item
}
# This displays the DirHash for all objects found when traversing the tree
Write-Host $hashValue $item
return $hashValue
}
# Just a test location - change to suit your own circumstances
$Location = "D:\Grant\Projects\xHashTest"
Get_Item_Hash $Location
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment