How to compare hash values of 2 different hash tables to prompt an action in either for loop or if statement?

Joe 40 Reputation points
2023-03-23T18:02:12.42+00:00

Hey, so I am trying to compare the values of 2 separate hash tables. I don't know if i should use a for loop, if statement or compare-object. My goal is to compare 2 hash tables both containing partition identifiers as the values and prompt a bcd /set as a result of any matching values.

$old_hash = [ordered]@{
	bootmain = "{xxxxxxxx-3af2-11ec-ac8e-111111a3f29}";
	boot1 = "{xxxxxxxx-3af2-11ec-ac8e-222222a3f29}";
	boot2 = "{xxxxxxxx-3af2-11ec-ac8e-333333a3f29}";
	boot3 = "{xxxxxxxx-3af2-11ec-ac8e-444444a3f29}";
	boot4 = "{xxxxxxxx-3af2-11ec-ac8e-555555a3f29}";
	boot5 = "{xxxxxxxx-3af2-11ec-ac8e-666666a3f29}";
	boot6 = "{xxxxxxxx-3af2-11ec-ac8e-7777773a3f29}";
}


$new_hash = [ordered]@{
	bootmain = "{xxxxxxxx-3af2-11ec-ac8e-222222a3f29}";
	boot1 = "{xxxxxxxx-3af2-11ec-ac8e-444444a3f29}";
	boot2 = "{xxxxxxxx-3af2-11ec-ac8e-666666a3f29}";
	boot3 = "{xxxxxxxx-3af2-11ec-ac8e-333333a3f29}";
	boot4 = "{xxxxxxxx-3af2-11ec-ac8e-0010183a3f29}";
	boot5 = "{xxxxxxxx-3af2-11ec-ac8e-7777773a3f29}";
	boot6 = "{xxxxxxxx-3af2-11ec-ac8e-555555a3f29}";
}

#I would set up the comparison to something like this:

foreach ($value in $old_hash.values) {
	if ($new_hash.boot1 -eq $value) {
		bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-444444a3f29}' description "1. Windows 10 - Moody 2301"
	}
	if ($new_hash.boot2 -eq $value) {
		bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-666666a3f29}' description "2. Windows 10 - Altamarino 2405"
	}
	if ($new_hash.boot3 -eq $value) {
		bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-333333a3f29}' description "3. Windows 10 - Delacruz 2415"
	}
	if ($new_hash.boot4 -eq $value) {
		bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-0010183a3f29}' description "4. Windows 10 - Defreitas 2405"
	}
	if ($new_hash.boot5 -eq $value) {
		bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-7777773a3f29}' description "5. Windows 10 - Thomas 2405"
	}
	if ($new_hash.boot6 -eq $value) {
		bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-555555a3f29}' description "6. Windows 10 - Ferez 2405"
	}
}

The issue with the foreach loop above is that I believe it would not properly loop through each value the way I want it to then just exit out of the loop with no changes or when it did find a match it would exit the loop after the first match and not keep going so maybe it would look like this:

#individual foreach loops going through each value of $old_hash and compare it too specific value of $new_hash

foreach ($value in $old_hash.values) {
	if ($new_hash.boot1 -eq $value) {
		bcdedit /set '{XXX-XXX-XX-XXX}' description "1. Windows 10 - Moody 2301"
	}
}

foreach ($value in $hash.values) {
    if ($new_hash.boot2 -eq $value) {
		bcdedit /set '{XXX-XXX-XX-XXX}' description "2. Windows 10 - Altamarino 2405"
	}
}

#there would end up being 6 separate foreach loops

Should I be using continue statements inside the first foreach loop to keep it from exiting the loop if there is a match found? I don't even know if this foreach statement would work in either case.

What do you think?

Windows 10
Windows 10
A Microsoft operating system that runs on personal computers and tablets.
11,469 questions
PowerShell
PowerShell
A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
2,455 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Michael Taylor 53,726 Reputation points
    2023-03-23T19:25:17.4866667+00:00

    A hashtable is just a dictionary. In your case you're really just using it to store a set of values and inside your loop you're actually looking at each value directly so the foreach loop isn't doing anything here. Just compare the values from the old and new hash directly.

    if ($new_hash.boot1 -ne $old_hash.boot1) {
    	bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-444444a3f29}' description "1. Windows 10 - Moody 2301"
    }
    if ($new_hash.boot2 -ne $old_hash.boot2) {
    	bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-666666a3f29}' description "2. Windows 10 - Altamarino 2405"
    }
    if ($new_hash.boot3 -ne $old_hash.boot3) {
    	bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-333333a3f29}' description "3. Windows 10 - Delacruz 2415"
    }
    if ($new_hash.boot4 -ne $old_hash.boot4) {
    	bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-0010183a3f29}' description "4. Windows 10 - Defreitas 2405"
    }
    if ($new_hash.boot5 -ne $old_hash.boot5) {
    	bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-7777773a3f29}' description "5. Windows 10 - Thomas 2405"
    }
    if ($new_hash.boot6 -ne $old_hash.boot6) {
    	bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-555555a3f29}' description "6. Windows 10 - Ferez 2405"
    }
    

    Notice here that the loop is gone and you're just comparing named-values in one hash to the other. I also believe you should be using not equal here instead of equal. This is the easiest approach given that for each key you are doing something different as far as the data is concerned.

    Of course this wouldn't scale to 100s of entries. At that point I would resort to storing the new data in an array where each array element was perhaps your hashed data but includes the specific data needed by your bcdedit call. Then you would use a foreach to enumerate the old hash key-values. For each key you'd look for the corresponding entry in your new array. If you found it then you would compare the GUIDs and if they don't match use the data (from the new array's element) to make your call to bcdedit. It might look something like this.

    foreach ($oldValue in $old_hash) {
       $newElement = # find the key in the new array's elements
       if ($newElement -and $newElement.id -ne $oldValue.id) {
          bcdedit /set $newElement.id description $newElement.description
       }
    }
    

    The thought here is that the new array is an array of objects where the objects have the value you need.

    $newElements = @(@{ name="boot1"; id = "guid"; description = 'Windows 10'), @{ ... })
    

    Of course you can build this array up dynamically if needed.

    0 comments No comments

  2. Rich Matheisen 46,551 Reputation points
    2023-03-23T20:00:52.19+00:00

    I made each "bcdedit" into a Write-Host and ran your hashes and code. The results were:

    Setting: bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-333333a3f29}' description "3. Windows 10 - Delacruz 2415"
    Setting: bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-444444a3f29}' description "1. Windows 10 - Moody 2301"
    Setting: bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-555555a3f29}' description "6. Windows 10 - Ferez 2405"
    Setting: bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-666666a3f29}' description "2. Windows 10 - Altamarino 2405"
    Setting: bcdedit /set '{xxxxxxxx-3af2-11ec-ac8e-7777773a3f29}' description "5. Windows 10 - Thomas 2405"
    
    

    So, it looks OK to me.

    Note: there's no 'description 4. . . .' because nothing in the "new" hash that matches the GUID ending in "555555a3f29" in the "old" hash. Also, the "old" GUID for boot6 is too long, as are the "new" GUIDs for boot4 and 5. Typos?

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.