Is PNPDeviceID of video card adapter unique? - c#

I need to get a unique id of video card adapter. When searching in the properties of the device (using Device Manager of Windows), I notice that there is a property named Hardware Ids as shown in image bellow.
I tried to get these Ids in my winform application. I found this method:
string VideoCardInfoID()
{
ManagementObjectSearcher objvide = new ManagementObjectSearcher("select * from Win32_VideoController");
string output = string.Empty;
foreach (ManagementObject obj in objvide.Get())
{
output += (obj["PNPDeviceID"] + "\n");
}
return output;
}
The output of this code is:
PCI\VEN_10DE&DEV_1055&SUBSYS_908A104D&REV_A1\4&F7451F8&0&0008
I have two questions:
Is PNPDeviceID of video card adapter unique across all machines? does it change when new fresh Windows installed? I know there some similar questions in stack overflow, but they does not contain a clear answers, such as this question and this question.
Why there is additional characters in the output of the c# function (\4&F7451F8&0&0008)?
Update: I try install new fresh Windows and the Hardware Ids and PNPDeviceID still the same, But I still don't know if PNPDeviceID unique across all machines (I mean the same as MAC address).

Is PNPDeviceID of video card adapter unique across all machines?
No. Essentially what this string is comprised of is
<Bus>\<Device ID>\<Instance ID>
The Instance ID is only unique within the context of the current system, and it may not even be unique for the whole system, only for the device's bus.
That is, if you have two identical video cards installed in the computer, they will have the same Device ID, but different Instance ID.
A graphics card driver might use its own serial number in the Instance ID. So it is possible that Instance ID is globally unique, but WMI cannot make that guarantee for all PNP devices.
At this point you will likely have to use a per-vendor documented way to determine the device's serial number, if at all possible.

Related

Win32_PnPEntity returning same ClassGuid for different hardware

I have some C# code scanning for plug and play devices and then filtering out 2 USB devices (call them dev1 and dev2) by matching VID and PID.
Now, dev1 is directly connected to a USB port of my laptop, while dev2 is connected to a USB Hub, that is connected to my docking station, that is connected to a different laptop USB port than dev1.
Dev1 and Dev2 are different hardware and VID+PID are therefore different for both. My script does detect the 2 different hardware with the correct (and different) VID+PID.
However, the GUID is the same for both Hardware. How can this be possible? Should they not be always different?
For info, here is how I am extracting the GUID and the VID+PID:
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(#"Select * From Win32_PnPEntity"))
collection = searcher.Get();
foreach (var device in collection)
{
string deviceIdValue = (string)device.GetPropertyValue("DeviceID"); // Provides VID and PID
string guidValue = (string)device.GetPropertyValue("ClassGuid"); // Provide the GUID
...
}
That's because ClassGuid is not an object identifier but a class identifier.
If you check out the PnPClass property you'll notice that it is the same when the ClassGuid is the same.
Check this link. It lists all the ClassGuid types.
The ClassGuid is not tigh to one piece of hardware, but rather to the type of class your hardware refers to.
For instance, two difference hardware of type USB, will both have the same ClassGuid {36FC9E60-C465-11CF-8056-444553540000} as per reference.

Retrieve name of bluetooth device from rfcomm device services

The context is the following, we have multiple trucks that contains a bluetooth to serial device, we have given each truck bluetooth a unique name to be able to connect to a specific truck.
I use this code to retrieve all the RFComm services :
DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort))
The problem is that all the DeviceInformation objects returned contains the name of the RFComm service in the Name property instead of the bluetooth device name. When my project was a Win 8 store app, all was fine since the name property contained the bluetooth device name.
I found that I could create a BluetoothDevice object using the device id returned by the above code, but then the app ask to use the bluetooth device for all devices until I find the good one. I would like to prevent that as it wasn't the case with Win 8 store app.
Second solution I found was to parse the device id of the RFComm service which look like this one
Bluetooth#Bluetooth00:c2:c6:56:b0:61-00:15:be:0f:02:d7#RFCOMM:00000000:{00001101-0000-1000-8000-00805f9b34fb}
to remove everything past "#RFCOMM" and use the DeviceInformation.CreateFromIdAsync() function. This works but I was wondering if there was a cleaner solution to my problem since parsing a string can be a real problem if the string format change.
Is there a way to retrieve the name of the bluetooth device without having to ask to use all bluetooth device until we find it?
You can try with following code to get the name of the Bluetooth device:
var serviceInfoCollection = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort), new string[] { "System.Devices.AepService.AepId" });
foreach (var serviceInfo in serviceInfoCollection)
{
var deviceInfo = await DeviceInformation.CreateFromIdAsync((string)serviceInfo.Properties["System.Devices.AepService.AepId"]);
System.Diagnostics.Debug.WriteLine($"Device name is: '{deviceInfo.Name}' and Id is: '{deviceInfo.Id}'");
}
The key point here is that Bluetooth device is one type of AssociationEndpoint objects. AEPs usually represent a device discovered over a wireless or network protocol. An AssociationEndpoint object is a child of a single AssociationEndpointContainer object and can contain 0 or more AssociationEndpointService objects. And RFComm service is one AssociationEndpointService that Bluetooth device contains. For more info, please see DeviceInformationKind enumeration and Enumerate devices over a network.
AssociationEndpointService has several properties. One of them is System.Devices.AepService.AepId which represents the identifier of the parent AssociationEndpoint object. So we can use this property to get the Bluetooth device information and once we get the device information, we can get the device name easily. However System.Devices.AepService.AepId property is not a commen property in DeviceInformation. So we need to use DeviceInformation.FindAllAsync(String, IIterable(String)) method to require this additional propertie. For more info, please see Device information properties.

Reading device serial number and/or IMEI from UWP app

I am working on an app that will obtain an X.509 certificate for a device that will be used to encrypt various configuration data. Ideally, this certificate would contain information that can be correlated with procurement records. Is there any way to read the device serial number or IMEI from a universal windows app?
As for UWP in general, to get a system unique id (not IMEI), you might want to check out these classes:
Windows.System.Profile.SystemIdentification
and
Windows.System.Profile.HardwareIdentification
E.g.: you can query a unique device id with:
var buffer = SystemIdentification.GetSystemIdForPublisher();
Which has the following remarks according to msdn:
The ID has the following characteristics:
Unique for every system
Can be created offline
Persists across rebooting, OS upgrades/reinstalls, and so on
Persists across hardware modifications
Available in OneCore
Available on the factory floor for licensing purposes
https://msdn.microsoft.com/en-us/library/windows/apps/windows.system.profile.systemidentification.getsystemidforpublisher.aspx
Be aware that the return type is an IBuffer and produces some raw (non-string-like-readable) bytes so you might need to serialize that.
More info
https://msdn.microsoft.com/en-us/library/windows/apps/windows.system.profile.systemidentification.aspx
and
https://msdn.microsoft.com/en-us/library/windows/apps/windows.system.profile.hardwareidentification.aspx
It is not possible to get IMEI of another phone with phone number information, however you can get the device unique Id.
using Microsoft.Phone.Info;
object uniqueId;
var hexString = string.Empty;
if (DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueId))
hexString = BitConverter.ToString((byte[])uniqueId).Replace("-", string.Empty);
MessageBox.Show("myDeviceID:" + hexString);
Reference

Get usb hardware or instance id using c#

I'am trying to get usb mass storage instance id for eject usb using devcon from last 2 days but not able to get that. I have tried alot of solutions but still failed.
ManagementObject dsk = new ManagementObject(#"win32_logicaldisk.deviceid=""j:""");
dsk.Get();
string id = dsk["VolumeSerialNumber"].ToString();
Console.WriteLine(id);
It returns instance id. when i pass this id to devcon it doesnt remove any device. Passing id to devcon in this way
Devcon remove usbstor\deviceID
is there any way to remove usb using device name as like G, H or I etc or get required instance id.
Any help will be appricated.
Try disabling UAC and also running devcon.exe under Administrator credentials.
I think #usblib can be helpfull for you , it allow you to play around usb divices #usblib

What is a good unique PC identifier?

I've been looking at the code in this tutorial, and I found that it uses My.Computer.Name to save settings that shouldn't roam between computers. It's entirely possible, however, for a user to have two identically named PCs. If they wanted to have the same username on each PC, for example, they may very well end up with two PCs named Username-PC.
What are some good methods of identifying different PCs? Do PCs have GUIDs associated with them, or should I look into pulling the serial number off of some hardware? I don't care if the identification persists through reinstallation of Windows.
(The tutorial I linked is in VB.Net, but I'm implementing it in C#)
Some good identifiers:
MAC Address: It's fairly easy to get at, and it's usually unique. However, it can be spoofed/changed rather easily, so it depends on how unique it needs to be.
CPU Serial Number: It's not available on lots of older systems, but it's there. Check out this MSDN page. It won't change, but it's bound to a computer.
HDD Serial Number: It's likely to not change, but can be a nuisance if the HD fails. Check out this MSDN page.
If you are on windows HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\ CurrentVersion\ProductId is unique per machine/per windows install. where as in some of the other answers like the MAC address, Proc SN, and HD SN will stay the same between windows reinstalls/dual boot situations.
The real answer to that question: There is no such thing.
There are several "close enough" solutions, but each one of those has it's own limitation.
All the hardware IDs - Hardware changes. And, in many cases you can change those identifiers (For example, MAC spoofing).
The SID, as I've already commented, Is not that good as well, because the SID won't change if the computer was installed from an image. The SID is generated by windows installation, if windows wasn't installed, but copied from an image, the SID won't change (although it is common to regenerate it because of a myth about "security risk" - you can't count on that).
Computer name - Well, as mentioned, They suppose to be unique, but it's not enforced in any way.
Another solution you can implement is to generate you own unique identifier and store it locally (assuming you can do such thing). Again, this solution won't work if your computer was imaged with your application.
The best solution for you really depends on what you are trying to accomplish.
I had the same problem with a quite large network, and the best solution in my case was the computer's name.
If you are absolutely sure that your process won't be imaged, I would generate a unique identifier using Guid because it will probably be the safest.
Here is a way to uniquely identify a computer.
Using System.Management to get Win32_BIOS, you can get unique values from your machine's BIOS.
See: Win32_BIOS class, http://msdn.microsoft.com/en-us/library/aa394077.aspx
using System.Management;
string UniqueMachineId()
{
StringBuilder builder = new StringBuilder();
String query = "SELECT * FROM Win32_BIOS";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
// This should only find one
foreach (ManagementObject item in searcher.Get())
{
Object obj = item["Manufacturer"];
builder.Append(Convert.ToString(obj));
builder.Append(':');
obj = item["SerialNumber"];
builder.Append(Convert.ToString(obj));
}
return builder.ToString();
}
With similar logic, you can also step through "Win32_DiskDrive";
http://msdn.microsoft.com/en-us/library/aa394132.aspx;
and get "SerialNumber" for each physical drive. In this case, the
foreach (ManagementObject item in searcher.Get())
should find multiple items
Take three identifiers that are semi-unique and semi-constant. Use the rule that 2 out of 3 is sufficient for a positive identification. Update the registered data for the 1 out of 3 that is occasionally wrong.
Use the network card's MAC address. It's supposed to be unique. It can be changed, though. It depends on how malicious you expect your users to be and how critical your application is.
Some sample code to do it:
public string GetMACAddress() {
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
string MACAddress = String.Empty;
foreach (ManagementObject mo in moc) {
if (MACAddress == String.Empty) { // only return MAC Address from first card
if ((bool)mo["IPEnabled"] == true) MACAddress = mo["MacAddress"].ToString();
}
mo.Dispose();
}
return MACAddress;
}
One thing you can use is the MAC of any Network interface. You can also combine several sources of information. Like HDD Serial number, mac, processor type to calculate a hash from it.
I don't think it's possible to have two PC's with the same name on the same domain. Have you tried capturing the domain name?
Take a look here: Getting Service Tag from Dell Machine using .net?
You could snatch some unique data from the registry.
Each computer has a SID that's unique under normal circumstances.
In a managed network environment, the best, most reliable identifier might be the one you create, but there are some downsides.
Some (many?) manufacturers provide a utility that allows you to set an asset tag that is stored in the firmware. This might be a bootable utility, or it might run within Windows, or it might even be built into the firmware setup. This "tag" is an arbitrary text string that you can set to whatever you want, and then read it back using WMI and the Win32_SystemEnclosure class...
string[] selectedProperties = new string[] { "SMBIOSAssetTag" };
ObjectQuery enclosureQuery = new SelectQuery("Win32_SystemEnclosure", null, selectedProperties);
using (ManagementObjectSearcher enclosureSearcher = new ManagementObjectSearcher(enclosureQuery))
using (ManagementObjectCollection enclosureCollection = enclosureSearcher.Get())
{
foreach (ManagementObject enclosure in enclosureCollection)
{
string assetTag = (string) enclosure.GetPropertyValue("SMBIOSAssetTag");
}
}
Pros:
You can use whatever scheme you want (e.g. incorporating date, department, incrementing integers, GUIDs, etc.).
You can use one scheme for all machines regardless of their manufacturer, instead of having to handle manufacturer-specific schemes.
By allocating and tracking the identifiers yourself, you can guarantee that they are unique. Not relying on an identifier set by the manufacturer means there is no risk of duplicates within a manufacturer or between manufacturers.
The identifier is stored in the firmware — not on the hard drive — so it will survive reformatting, upgrades, etc. but also not be duplicated by backups/imaging/cloning.
Cons:
You need to actually set the asset tag; they'll all be blank until you do so.
Setting a machine's asset tag may require physical access and a reboot.
Asset tags are not write-once and could, therefore, be changed or erased.
Password-protected firmware should require that password before changing the tag, but that's not guaranteed.
By allocating and tracking the identifiers yourself, there's not only the overhead of...allocating and tracking the identifiers, but also the possibility that you'll introduce duplicates if you're not careful.
Using asset tags for this purpose requires that all machines support setting an asset tag and properly report it to WMI.
We use a combination of the ProcessorID from Win32_processor and the UUID from Win32_ComputerSystemProduct:
ManagementObjectCollection mbsList = null;
ManagementObjectSearcher mos = new ManagementObjectSearcher("Select ProcessorID From Win32_processor");
mbsList = mos.Get();
string processorId = string.Empty;
foreach (ManagementBaseObject mo in mbsList)
{
processorId = mo["ProcessorID"] as string;
}
mos = new ManagementObjectSearcher("SELECT UUID FROM Win32_ComputerSystemProduct");
mbsList = mos.Get();
string systemId = string.Empty;
foreach (ManagementBaseObject mo in mbsList)
{
systemId = mo["UUID"] as string;
}
var compIdStr = $"{processorId}{systemId}";
Previously, we used a combination: processor ID ("Select ProcessorID From Win32_processor") and the motherboard serial number ("SELECT SerialNumber FROM Win32_BaseBoard"), but then we found out that the serial number of the motherboard may not be filled in, or it may be filled in with uniform values:
To be filled by O.E.M.
None
Default string
Therefore, it is worth considering this situation.
Also keep in mind that the ProcessorID number may be the same on different computers.
There is a sample code with complete notes in this link for getting CPU and HD Drive ID: http://www.vcskicks.com/hardware_id.php
add this dll to refrences
System.Management.dll
for CPU ID:
string cpuInfo = string.Empty;
ManagementClass mc = new ManagementClass("win32_processor");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if (cpuInfo == "")
{
//Get only the first CPU's ID
cpuInfo = mo.Properties["processorID"].Value.ToString();
break;
}
}
return cpuInfo;
and for Hard Drive ID (Volume Serial):
ManagementObject dsk = new ManagementObject(#"win32_logicaldisk.deviceid=""" + drive + #":""");
dsk.Get();
string volumeSerial = dsk["VolumeSerialNumber"].ToString();

Categories