0

For our licensing / software activation we need to uniquely identify a computer. To do that we're relying on WMI and we're building a unique computer key using BIOS Version, ProcessorID, MainHardDrive serial etc.... It's working great since 4-5 years but we recently have some customers that complains about activation issues.

After some investigations we find that the problem is not new, it exists since the beginning and WMI values seems to be different from an app start to another...

Here is a sample of some customer data that have changed in 2 days :

wmi values differences

(on the left "good" data, on the right "inconsistent" empty values)

Sometimes we have users with a corrupted WMI : values are empty or I catch an exception in my code, nothing fancy. In this case a WMI reparation does the job. But it's the first time we're facing inconsistent data...

Thanks for your help !

EDIT : Here's how I retrieve WMI values :

private static Dictionary<string, string> GetBiosInfo()
{
    Dictionary<string, object> classIdentifiers = GetIdentifiers("Win32_BIOS");

    Dictionary<string, string> biosInfo = new Dictionary<string, string>
    {
        { BiosInfo_Manufacturer, GetIdentifier(classIdentifiers, "Manufacturer") },
        { BiosInfo_SMBIOSBIOSVersion, GetIdentifier(classIdentifiers, "SMBIOSBIOSVersion") },
        { BiosInfo_IdentificationCode, GetIdentifier(classIdentifiers, "IdentificationCode") },
        { BiosInfo_SerialNumber, GetIdentifier(classIdentifiers, "SerialNumber") },
        { BiosInfo_ReleaseDate, GetIdentifier(classIdentifiers, "ReleaseDate") },
        { BiosInfo_Version, GetIdentifier(classIdentifiers, "Version") }
    };
    return new Dictionary<string, string>(biosInfo);
}

private static Dictionary<string, object> GetIdentifiers(string wmiClass, int tryNumber = 0)
{
    if (tryNumber == 0)
    {
        _timers.Add(wmiClass, DateTime.Now);
    }

    try
    {
        ManagementClass mc = new ManagementClass(wmiClass);
        ManagementObjectCollection moc = mc.GetInstances();

        Dictionary<string, object> values = new Dictionary<string, object>();
        foreach (var mo in moc)
        {
            foreach (var item in mo.Properties)
            {
                if (!values.ContainsKey(item.Name))
                {
                    values.Add(item.Name, item.Value);
                }
            }

            foreach (var item in mo.SystemProperties)
            {
                if (!values.ContainsKey(item.Name))
                {
                    values.Add(item.Name, item.Value);
                }
            }
        }

        return values;
    }
    catch (Exception e)
    {
        if (tryNumber <= 200)
        {
            tryNumber = tryNumber + 1;
            return GetIdentifiers(wmiClass, tryNumber);
        }
        else
        {
            // Si après 200 essais on arrive toujours pas à obtenir les informations on laisse tomber
            // on crée une exception spécifique
            GetIdentifiersException newException = new GetIdentifiersException(string.Format("Erreur interne dans la méthode SystemHelper.GetIdentifiers (appel de la méthode GetInstances)...  / WMIClass : {0} / Essai n°{1} / Durée : {2} ms", wmiClass, tryNumber, (DateTime.Now - _timers[wmiClass]).TotalMilliseconds), e);
            // on renvoi l'exception pour l'attraper dans la classe appelante (VBActivation)
            throw newException;
        }
    }
}

private static string GetIdentifier(Dictionary<string, object> classIdentifiers, string wmiProperty)
{
    string result = string.Empty;

    if (classIdentifiers != null && classIdentifiers.ContainsKey(wmiProperty))
    {
        result = classIdentifiers[wmiProperty] != null ? classIdentifiers[wmiProperty].ToString() : string.Empty;
    }

    return result;
}
Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
David CASBONNE
  • 139
  • 2
  • 9
  • i do not know how you are getting this info from WMI, but clearly something is going wrong when all 'emtpy' values are fetched. This has noting to do with being 'inconsitent', but with error checking when getting the values. You need to check if the values are 'valid' (in this case <>'') . – Luuk Feb 18 '20 at 17:17
  • 2
    Is it possible the program is being run under different credentials each time? Maybe on the second run the user was different (non-admin?) and therefore the MacAddress et al. came back as blank. – nollidge Feb 18 '20 at 20:01
  • @Luuk see edit on main post on how I retrieve values. It works and suddenly it stops working. And 50ms later it works again. I think I have a good error check but maybe you would find something wrong in my code... For me its the definition of being inconsistent :) – David CASBONNE Feb 19 '20 at 19:32
  • @nollidge unfortunately it's in the instance of the app when it's working and failing 50ms later... But it was a good idea ! – David CASBONNE Feb 19 '20 at 19:33
  • Does it usually go beyond a `tryNumber` of `0` to get a result? That is, are there exceptions being caught within `GetIdentifiers()` such that it tries again and, if so, what are they? If it's a `ManagementException` you'd want to check the `ErrorCode` property to see what the failure was. The issue I see with `GetIdentifier()` is that you can't tell the difference between a property was not returned (not sure how/if that could ever happen) vs. a property is `null` vs. a property is an empty string because it returns `string.Empty` in all 3 cases. – Lance U. Matthews Feb 19 '20 at 20:08
  • @BACON it's hard to say because when it works when didn't have any call from customers :) We have had exceptions caught within this method but I'm unable to find one on my computer... Usually it stands for a broken WMI. So we repair it and everything works like a charm. When reviewing my code before posting I also remark the problem with ```string.Empty```. I want to change that but I have to be very careful as more than 5000 customers relies on this code to have their software activate ! – David CASBONNE Feb 21 '20 at 13:00

0 Answers0