so I saw the other answers on here and needed to chime in.
found
strings /sys/firmware/acpi/tables/MSDM
works great if the original key is what is still being used. However I have some systems that came with the home addition and you need to get the current key from the registry.
winmount=/mnt
echo "hex \\Microsoft\\Windows NT\\CurrentVersion\\DigitalProductId\nq\nq" | chntpw -e ${winmount}/Windows/System32/config/SOFTWARE
then we will need to run it through an algorithm to get the key.
I found some code from https://github.com/mrpeardotnet/WinProdKeyFinder/blob/master/WinProdKeyFind/KeyDecoder.cs
    /// <summary>
    /// Decodes Windows Product Key from the DigitalProductId. 
    /// This method applies to DigitalProductId from Windows 7 or lower versions of Windows.
    /// </summary>
    /// <param name="digitalProductId">DigitalProductId to decode</param>
    /// <returns>Decoded Windows Product Key as a string</returns>
    private static string DecodeProductKey(byte[] digitalProductId)
    {
        const int keyStartIndex = 52;
        const int keyEndIndex = keyStartIndex + 15;
        var digits = new[]
        {
            'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R',
            'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9',
        };
        const int decodeLength = 29;
        const int decodeStringLength = 15;
        var decodedChars = new char[decodeLength];
        var hexPid = new ArrayList();
        for (var i = keyStartIndex; i <= keyEndIndex; i++)
        {
            hexPid.Add(digitalProductId[i]);
        }
        for (var i = decodeLength - 1; i >= 0; i--)
        {
            // Every sixth char is a separator.
            if ((i + 1) % 6 == 0)
            {
                decodedChars[i] = '-';
            }
            else
            {
                // Do the actual decoding.
                var digitMapIndex = 0;
                for (var j = decodeStringLength - 1; j >= 0; j--)
                {
                    var byteValue = (digitMapIndex << 8) | (byte)hexPid[j];
                    hexPid[j] = (byte)(byteValue / 24);
                    digitMapIndex = byteValue % 24;
                    decodedChars[i] = digits[digitMapIndex];
                }
            }
        }
        return new string(decodedChars);
    }
    /// <summary>
    /// Decodes Windows Product Key from the DigitalProductId. 
    /// This method applies to DigitalProductId from Windows 8 or newer versions of Windows.
    /// </summary>
    /// <param name="digitalProductId">DigitalProductId to decode</param>
    /// <returns>Decoded Windows Product Key as a string</returns>
    public static string DecodeProductKeyWin8AndUp(byte[] digitalProductId)
    {
        var key = String.Empty;
        const int keyOffset = 52;
        var isWin8 = (byte)((digitalProductId[66] / 6) & 1);
        digitalProductId[66] = (byte)((digitalProductId[66] & 0xf7) | (isWin8 & 2) * 4);
        const string digits = "BCDFGHJKMPQRTVWXY2346789";
        var last = 0;
        for (var i = 24; i >= 0; i--)
        {
            var current = 0;
            for (var j = 14; j >= 0; j--)
            {
                current = current*256;
                current = digitalProductId[j + keyOffset] + current;
                digitalProductId[j + keyOffset] = (byte)(current/24);
                current = current%24;
                last = current;
            }
            key = digits[current] + key;
        }
        var keypart1 = key.Substring(1, last);
        var keypart2 = key.Substring(last + 1, key.Length - (last + 1));
        key = keypart1 + "N" + keypart2;
        for (var i = 5; i < key.Length; i += 6)
        {
            key = key.Insert(i, "-");
        }
        return key;
    }
I'm going to try and decode the algorithm and write it in bash.
The dmi output seems to be the older algorithm (<win8) for decoding the key. I have not found an option for using the new algorithm (>win7).