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
This will certainly come in handy. Thank you
Sent from my iPhone
>
LikeLike
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?
LikeLike
I was trying to compare nested objects.
LikeLike
Your function is using $md5 but doesn’t define it.
LikeLike
ahhh… darn it… I forgot to add it… I’ll add it back thank you for the catch
LikeLike
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 <=
LikeLike
Ok I’ll look into it.
LikeLike
the problem is the fact that the difference and reference variables to do what I’m looking for must be of type [object] I’ll correct it in my example.
LikeLike
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.
LikeLike
yes sir… that is what I found as well… thank you for spotting that..
LikeLike