Different Autopilot Hardware Hashes from the Same Device

If you’re in the business of collecting Hardware Hashes for Autopilot device registration, you may have noticed that the hash from a device can change when you collect them at different times. How is this possible? Isn’t a hash supposed to be unique to each device? How does a hardware hash change if none of the hardware components have changed?

It turns out the term “hardware hash” is a bit of a misnomer in this case as the ‘hash’ is really just a base64 encoding of XML formatted text, and it is not truly a hash at all. So, it’s an unfortunate name for the thing, but what else would you call it?

The hardware ‘hash’ does in fact change if you harvest it multiple times from the same device, and I’m not sure I would call this “by design” but it certainly is expected, and documented. The reason it changes is because the ‘hash’ contains the date and time that it was collected. And since those values will be different depending on when you harvest it, the base64 encoding of those values (the ‘hash’) will also be different every time you generate it (and yes, I’m using the terms collect, harvest and generate interchangeably here).

The hardware hash changes each time it’s generated because it includes details about when it was generated.

Microsoft Docs

Thankfully, these date/time attributes are not used to identify a device for Autopilot registration, so the fact a device produces different hashes at different times is not a problem. But it can be confusing…

How a Hardware Hash is Made

For some more context, first look at the Get-WindowsAutopilotInfo.ps1 script. There you will find Get-CimInstance being used to pull the DeviceHardwareData property out of the MDM_DevDetail_Ext01 class.

$session = New-CimSession
# Get the hash (if available)
$devDetail = (Get-CimInstance -CimSession $session -Namespace root/cimv2/mdm/dmmap -Class MDM_DevDetail_Ext01 -Filter "InstanceID='Ext' AND ParentID='./DevDetail'")
if ($devDetail -and (-not $Force))
{
    $hash = $devDetail.DeviceHardwareData
}

For our exploration we’ll just use the first line to get the value in the $devDetail variable.  If you print the content of $devDetail, you’ll see the DeviceHardwareData has the “base64-encoded string of the hardware parameters of a device.”

If you check it again, you’ll notice that the value has changed, just a little bit.

NOTE: The fact that most of this text is the same between runs is a good clue that this is not truly a hash but instead it’s an encoding of content. If it were a true hash, the whole string would be wildly different (and probably a lot shorter) even if the input were to change just slightly.

Decoding the Hardware Hash

Since the docs say this is a base64 encoded string, let’s decode it to see what it is. With PowerShell, we can use FromBase64String to get the decoded content.

[System.Convert]::FromBase64String($devDetail.DeviceHardwareData)

Well, that’s not real useful, is it? Just a bunch of numbers, all on their own lines. That’s because FromBase64String returns “An array of 8-bit unsigned integers” and that’s what we’re seeing here. We still need to convert this to a text encoding like UTF-8 or ASCII so we can try reading it.

[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($devDetail.DeviceHardwareData))

Sadly, the results are not much better, but at least some of it is legible. What we’re looking at is binary data with some strings in it. This data just happens to have been created using the “OEM Activation 3.0 system” and that is where the “Hardware Hash” got its name from. In other words, the “hardware hash” is NOT an Autopilot thing, it’s a Windows Product Activation thing.

To decode these values, we can use one of the diagnostic features of the “OEM Activation Tool 3.0” by downloading and installing the Deployment Tools part of the Windows ADK.

This will give you oa3tool.exe located in 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Licensing\OA30\' and we want to feed it the encoded ‘hash’ value using the /DecodeHwHash switch.

$session = New-CimSession
$devDetail = (Get-CimInstance -CimSession $session -Namespace root/cimv2/mdm/dmmap -Class MDM_DevDetail_Ext01 -Filter "InstanceID='Ext' AND ParentID='./DevDetail'")
& 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Licensing\OA30\oa3tool.exe' /DecodeHwHash="$($devDetail.DeviceHardwareData)"

Now we can clearly see the “OsSystemTime” and “OsLocalTime” attributes that are contained in the ‘hash’. In this example the timestamps end at :25 seconds.

And if we run the same commands, even just a few seconds later, we’ll see the timestamps reflect the new time, which in this case is at :46 seconds. This change in the timestamp is the reason the hashes are different, but because they are not used for the Autopilot device registration, the change is not an issue.

NOTE: Autopilot only uses a subset of the attributes found in the “Hardware hash”, but the entire string is sent to the service and then parsed there for registration. These attributes include:

  • ProductKeyID
  • SmbiosSystemManufacturer
  • SmbiosSystemProductName
  • SmbiosSystemSerialNumber
  • SmbiosSkuNumber
  • SmbiosSystemFamily
  • MacAddress
  • SmbiosUuid
  • DiskSerialNumber
  • TPM EkPub

What does it mean?

So now that we know where the Hardware hash comes from, and why the Autopilot hash changes if you try to collect it multiple times, what does that mean? Let’s make a list!

  • A ‘hardware hash’ is really a just a poor name for some encoded values (it’s not a hash!)
  • A device does NOT have a unique ‘hardware hash’ (it changes every time it’s collected!)
  • Hashes collected at different times CANNOT be compared to find a “matching device”
  • Hashes from the script will NOT match hashes in the ConfigMgr report (unless they happen to be collected at exactly the same time!)
  • More recently collected hashes are NOT “better” than older hashes (if the hardware hasn’t changed!)

Anyway, I hope that helps!

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 )

Twitter picture

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

Facebook photo

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

Connecting to %s