Just Hash It


I have been looking high and low for a good means to compare one variable to another and do it quickly.  In my search I found this article on Stack Over flow.  This led me to create a function that you could use for comparing one variable to another and getting a simple $true or $false answer if they are the same or not.   This article explains that concept

To start with I need to create a function block and pass two parameters. The item i’m using as a reference $reference and the item/variable I’ll use as the difference.


function Compare-Variables
{
param([string]$Reference, [string]$difference)

}

Using the example from the Post on Stack overflow I need to create an Object to hold the text encoding System.Text.UTF8Encoding  System.Security.Cryptography.MD5CryptoServiceProvider and a System.BitConverter.

To work backwards from the object to the comparison here is what takes place.

Step 1: Take the contents of each variable and turn them in to json – Using Converto-Json

$ref = $reference.CacheValue | ConvertTo-Json -Depth 100
$diff = $difference.CacheValue | ConvertTo-Json -Depth 100 

Now that I have it in a json object (so long as the object isn’t nested beyond 100) I’ll have the entire variable and it’s children objects.  This is in a variable called $ref and $diff.

Step 2: Since I have those in a variable I can get the bytes for the variable from Calling the UTF8 getBytes method.  Using a variable of test you’ll see that I get back a set of bytes for each character:


$utf8 = [System.Text.UTF8Encoding]::new()

$utf8.GetBytes('test')
116
101
115
116 

Step 3: Now that my variable is in bytes I can now compute a hash for those bytes with the System.Security.Cryptography.MD5CryptoServiceProvider


$md5 = [System.Security.Cryptography.MD5CryptoServiceProvider]::new()
$md5.ComputeHash($utf8.GetBytes('test'))
9
143
107
205
70
33
211
115
202
222
78
131
38
39
180
246 

Step 4: Now that I have my Computed hash I can convert this into a readable MD5 Sum with  System.BitConverter.

[System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes('test')))
09-8F-6B-CD-46-21-D3-73-CA-DE-4E-83-26-27-B4-F6
 

Step 5: Now that I have that for both my variables I can simply ask if $ref -eq $diff and get an answer of $true or $false.

Completed Script is below:

function Compare-Variables
{
 param([object]$Reference, [object]$difference, [int]$objectDepth='2')
 $utf8 = [System.Text.UTF8Encoding]::new()
 $match = $false
 $md5 = [System.Security.Cryptography.MD5CryptoServiceProvider]::new()
 $ref = $reference | ConvertTo-Json -Depth $objectDepth
 $diff = $difference | ConvertTo-Json -Depth $objectDepth
 $hashref = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($ref)))
 $hashdif = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($diff)))
 $match = $hashref -eq $hashdif
 $hashref = $diff = $ref = $utf8 = $md5 = $null
 $match
}
 

Testing this Function:

Simple Test with just text: Now I can call this function and get a $true if the variables match and a false if they don’t.

$a = 'test'
$b = 'test'
Compare-Variables -Reference $a -difference $b
True
$a = 'test2'
$b = 'test'
Compare-Variables -Reference $a -difference $b
False

Test with an object from a Rest API: Now lets try something that we know will have a fair amount of data in it.  Githubs Rest Api:

 $a = 'test'
$b = 'test'
Compare-Variables -Reference $a -difference $b
True
$a = Invoke-RestMethod -uri http://api.github.com
$b = Invoke-RestMethod -Uri http://api.github.com
Compare-Variables -Reference $a -difference $b
True
$a = Invoke-RestMethod -Uri http://api.github.com/emojis
$b = Invoke-RestMethod -uri http://api.github.com
 Compare-Variables -Reference $a -difference $b
Flase

I hope this helps someone

Until then keep Scripting

Thom

 

 

 

Advertisement

10 thoughts on “Just Hash It

  1. Jeffery Hicks

    What where the limitations with Compare-Object? For simple variables that would work just as well.
    $a=1
    $b=1
    Compare-object $a $b
    For more complicated objects you can compare a property. Or is your function really intended to compare a specific type of object?

    Like

  2. Jeffery Hicks

    Something doesn’t seem right with this approach:
    PS C:\> $a = gsv bits
    PS C:\> $b = gsv bits
    PS C:\> compare-variables $a $b
    True
    PS C:\> $b = gsv winrm
    PS C:\> compare-variables $a $b
    True

    I would expect the last test to be False.

    PS C:\> compare-object $a $b

    InputObject SideIndicator
    ———– ————-
    winrm =>
    bits <=

    Like

  3. Jeffery Hicks

    I think you made a function for a very specific use case. I just noticed that because the reference and difference variables are treated as strings. when I run $a = get-service bits, the function will treat it as “System.ServiceProcess.ServiceController”. That’s why my service variables always matched. I changed the parameter types to [object] and now I’m going down the path I think you intended.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s