问题
In the Windows SDK there is a CLI tool named computerhardwareids
The tool returns various GUIDs to select the proper HardwareId for the specific case.
This is the output that returns this tool in my PC:
Using the BIOS to gather information
Computer Information
--------------------
BIOS Vendor: American Megatrends Inc.
BIOS Version string: 1201
System BIOS Major Release: 4
System BIOS Minor Release: 6
System Manufacturer: To be filled by O.E.M.
System Family: To be filled by O.E.M.
System ProductName: To be filled by O.E.M.
SKU Number: SKU
Enclosure Type: 03 "Desktop"
Hardware IDs
------------
{a8670b03-1d98-5e95-ad4e-c64211eac9df} <- Manufacturer + Family + ProductName + SKUNumber + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
{01c6b2a2-a2b2-58e4-906d-4677639f1a42} <- Manufacturer + Family + ProductName + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
{dc5af3fe-c2de-539d-aafd-5061a1634723} <- Manufacturer + ProductName + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
{d78b474d-dee0-5412-bc9d-e9f7d7783df2} <- Manufacturer + Family + ProductName + SKUNumber
{7ccbb6f1-9641-5f84-b00d-51ff218a4066} <- Manufacturer + Family + ProductName
{5a127cba-be28-5d3b-84f0-0e450d266d97} <- Manufacturer + SKUNumber
{6525c6e5-28e9-5f9c-abe4-20fd82504002} <- Manufacturer + ProductName
{6525c6e5-28e9-5f9c-abe4-20fd82504002} <- Manufacturer + Family
{482f3f58-6045-593a-9be4-611717ce4770} <- Manufacturer + Enclosure Type
{11b4a036-3b64-5421-a372-22c07df10a4d} <- Manufacturer
I would like to develop a generic use function that should mimic the functionality of that Microsoft tool, returning exactly the same HardwareIds (exactly the same).
I've found info on MSDN, all the output seems very documented and it contains info about the values that returns this tool, but it does not specify exactly what properties of the WMI classes are, it just says "Bios" and "System":
· ComputerHardwareIds Overview
· Specifying Hardware IDs for a Computer
I'm very lost, I can't find any values such as "Family", "BIOS Vendor", "Bios Major Release", "Bios Minor Release" and I'm not sure where the "SKU Number" refers to.
I Think these are the WMI Classes where the tool obtains part of all the data to make the guid:
· Win32_BIOS class
· Win32_BaseBoard class
· Win32_ComputerSystem class
· Win32_ComputerSystemProduct class
Note that the documentation also says this:
Each string is then converted into a GUID by using the SHA-1 hashing algorithm.
This is what I've tried to do, but I'm not sure whether i'm wrong with some concept or some values, it's incomplete and I also have problems with the Guis (explained with commentlines):
Private Function GetHardwareId() As Guid
Dim HardwareId As String = String.Empty
Dim BIOSVersion, BIOSVendor, BIOSMajorRelease, BIOSMinorRelease,
SystemManufacturer, SystemFamily, SystemProductName, SKUNumber As String
' Get System Info.
Using wmi As New Management.ManagementObjectSearcher("select * from Win32_ComputerSystem")
Using SystemInfo As Management.ManagementObject = wmi.Get(0)
SystemManufacturer = Convert.ToString(SystemInfo.Properties("Manufacturer").Value)
SystemProductName = Convert.ToString(SystemInfo.Properties("Model").Value)
SystemFamily = I don't know how to get it.
SKUNumber = I don't know how to get it.
End Using
End Using
' Get BIOS Info.
Using wmi As New Management.ManagementObjectSearcher("select * from Win32_BIOS")
Using BIOSInfo As Management.ManagementObject = wmi.Get(0)
BIOSVersion = Convert.ToString(BIOSInfo.Properties("SMBIOSBIOSVersion").Value)
BIOSVendor = I don't know how to get it.
BIOSMajorRelease = I don't know how to get it.
BIOSMinorRelease = I don't know how to get it.
End Using
End Using ' wmi
HardwareId = BIOSVersion & BIOSVendor & BIOSMajorRelease & BIOSMinorRelease &
SystemManufacturer & SystemFamily & SystemProductName & SKUNumber
' Here I call other method to encode the resulting string to SHA1 Hash
HardwareId = ConvertToSHA1(HardwareId)
' and then continue below...
' But this will not work,
' it throws an exception about missing "-" chars in the SHA1 string.
' So Microsoft formats "manualy" the SHA1 string to add some "-"?
Return Guid.Parse(HardwareId)
End Function
回答1:
To generate the same GUIDs you need to get the values from SMBIOS (typically using GetSystemFirmwareTable), and then join them using the '&' char. Make sure the strings are encoded with UTF-16. You then need to use a type 5 (SHA-1) UUID generation scheme with 70ffd812-4c7f-4c7d-0000-000000000000 as the namespace.
回答2:
I dont think your problem can be solved the way you want. But there is also no reason to, as yet.
MS is creating deterministic GUIDs from a SHA hash of the various data provided. If created according to the rfc422 standards which includes one of the 4 defined GUID namespaces, we should be able to recreate the GUID from the same data using one of those 4 namespaces.
However, a) I can't and b) MSDN's 'Specifying Hardware IDs for a Computer' states: the hardware ID for the computer must be produced by the ComputerHardwareIds tool (ComputerHardwareIDs.exe)...
. This leads me to believe they use a proprietary method (Salt, private Key etc) or defined their own namespace to generate these.
Some answers to your secondary/sub questions:
- BIOS Version/Release - According to the DTMF.org spec, Table 5 "Release" are at offset &H14 and &H15 and are different than "Version". However, they may also be embedded in the Name, Caption, Description and SoftwareElementID properties of
Win32_BIOS
(see tool below). It also seems to be tucked away inWin32_BIOS.BiosVersion(1)
but it is the same as Name/Caption etc.
I find it a bit curious that our systems are several years apart but have the same Release values, it may refer to the SMBios release/spec.
SKU: According to MSDN, this is AKA
IdentificationCode
Family: Apparently part of the BIOS encoding, but WMI does not expose or return it (yet?).
The same is true for Product Name, the
Model
you fetch from elsewhere may have the same value only by coincidence.
So, it does not appear the values used in the hash are all exposed. On my older system, Family and SKU are null. As a result, it seems that the first and second ID should be the same, but they are not.
I am not sure what these are for or how they are of much value to the average app if the GUID/ID is only available from that tool. You might poke around other parts of the SDK to see if there are assemblies or such to provide the info at run time.
If you simply want to recognize a system or device the next time you see it, you could simply write your own method based on rfc422 to assure the very same 'very high probability' of a unique value within a namespace you define. The only reason to do it just like MS is if you were going to see that value coming from elsewhere, which is not the case.
Finally, I did not bother posting the GUID maker since it won't do what you want anyway.
WMI helpers to fetch property values:
Public Sub GetWMIInfo(wmiclass As String)
Using searcher As New Management.ManagementObjectSearcher("select * from " & wmiclass)
For Each item As System.Management.ManagementObject In searcher.Get
DebugProperties(item)
Next
End Using
End Sub
' this sub is copied from the watcher answer I gave:
Private Sub DebugProperties(mo As Management.ManagementObject)
For Each pd As PropertyData In mo.Properties
If pd.Value IsNot Nothing Then
' some props are string arrays, so you can iterate them if you want
Console.WriteLine("{0} {1}", pd.Name,
If(pd.Value IsNot Nothing,
pd.Value.ToString,
"Nothing"))
End If
Next
End Sub
Output is like this:
Caption BIOS Date: XXXXXXXXXXXX Ver: 04.06.04
Description BIOS Date: ##/##/## 11:18:49 Ver: 04.06.04
Manufacturer Dell Inc.
Name BIOS Date: ##/##/## 11:18:49 Ver: 04.06.04
PrimaryBIOS True
ReleaseDate ########000000.000000+000
SerialNumber ######
SMBIOSBIOSVersion A##
SMBIOSMajorVersion #
SMBIOSMinorVersion #
回答3:
public ArrayList<String> getWinVendor()
throws SecurityException, IOException,
NullPointerException, IndexOutOfBoundsException,
UnsupportedEncodingException {
try {
Process processProduct = Runtime.getRuntime().exec(new String[]{"wmic", "csproduct", "get", "vendor"});
processProduct.getOutputStream().close();
BufferedReader output = getOutput(processProduct);
BufferedReader error = getError(processProduct);
StringProductList = new ArrayList<String>();
String line = "", result = "";
while ((line = output.readLine()) != null) {
if (!line.toLowerCase().startsWith("vendor") && line.length() > 0) {
result = getSubStringSubstractEmptyAndTabSpace(line);
if (result.length() > 0) {
StringProductList.add(result);
} else {
StringProductList.add(UNKNOWN);
}
}
}
if (!StringProductList.isEmpty()) {
return StringProductList;
}
} catch (Exception e) {
if (e instanceof SecurityException
|| e instanceof IOException
|| e instanceof NullPointerException
|| e instanceof IndexOutOfBoundsException
|| e instanceof UnsupportedEncodingException) {
e.printStackTrace();
}
}
return null;
}
public BufferedReader getError(Process process) throws SecurityException, IOException,
NullPointerException, IndexOutOfBoundsException, UnsupportedEncodingException {
try {
if (getCmdEncoding() != null) {
return new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
}
} catch (Exception e) {
if (e instanceof SecurityException
|| e instanceof IOException
|| e instanceof NullPointerException
|| e instanceof IndexOutOfBoundsException) {
e.printStackTrace();
}
}
return new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
}
public BufferedReader getOutput(Process process) throws SecurityException, IOException,
NullPointerException, IndexOutOfBoundsException, UnsupportedEncodingException {
try {
if (getCmdEncoding() != null) {
return new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
}
} catch (Exception e) {
if (e instanceof SecurityException
|| e instanceof IOException
|| e instanceof NullPointerException
|| e instanceof IndexOutOfBoundsException) {
e.printStackTrace();
}
}
return new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
}
public static String getSubStringSubstractEmptyAndTabSpace(String word)
throws NullPointerException, IndexOutOfBoundsException {
if (word.length() > 0) {
try {
int length = word.length();
int start = 0, end = length;
for (int stringCharacter = 0; stringCharacter < length; stringCharacter++) {
char c = word.charAt(stringCharacter);
if (c == ' ' || c == '\t') {
start++;
} else {
stringCharacter = length;
}
}
for (int stringCharacter = length - 1; stringCharacter >= 0; stringCharacter--) {
char c = word.charAt(stringCharacter);
if (c == ' ' || c == '\t') {
end--;
} else {
stringCharacter = -1;
}
}
if (start == length) {
return "";
}
if (end == 0) {
return "";
}
if (start <= length - 1 && end >= 0) {
return word.substring(start, end);
}
} catch (Exception e) {
if (e instanceof NullPointerException
|| e instanceof IndexOutOfBoundsException) {
e.printStackTrace();
}
}
}
return word;
}
来源:https://stackoverflow.com/questions/25190906/get-hardware-ids-like-microsoft-does