How do I generate a unique number for every computer? [duplicate] - c#

This question already has answers here:
How to uniquely identify computer using C#?
(5 answers)
Closed 6 years ago.
I am working on a software lock using C#. I need to generate a unique number for every computer.
I have researched and decided to use the CPU number and hard drive number as a unique number for every computer.
My Code :
private string UniqID()
{
////////////////CpuID
string cpuInfo = string.Empty;
ManagementClass mc = new ManagementClass("win32_processor");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
cpuInfo = mo.Properties["processorID"].Value.ToString();
break;
}
////////////////HDD ID
string drive = "C";
ManagementObject dsk = new ManagementObject(
#"win32_logicaldisk.deviceid=""" + drive + #":""");
dsk.Get();
string volumeSerial = dsk["VolumeSerialNumber"].ToString();
return volumeSerial + cpuInfo;
}
That works, but there is a problem!
When a user re-installs Windows (OS) and wants to run my software, the unique number has been changed.
Why does the unique number change when Windows is installed again? Do the CPU number and HDD number depend on the current windows installation?

You realistically have MotherboardID, CPUID, Disk Serial and MAC address, from experience none of them are 100%.
Our stats show
Disk serial Is missing 0.1 %
MAC Is missing 1.3 %
Motherboard ID Is missing 30 %
CPUID Is missing 99 %
0.04% of machines tested they yielded no information, we couldn't even read the computer name. It maybe that these were some kind over virtual PC, HyperV or VMWare instance?
Disk serial is the most reliable, but easy to change, mac can be changed and depending on the filtering applied can change if device drivers are added (hyperv, wireshark etc).
Motherboard and CPUID sometimes return values that are placeholders "NONE" etc.
You should also note that these functions can be very slow to call (they may take a few seconds even on a fast PC), so it may be worth kicking them off on a background thread as early as possible, you ideally don't want to be blocking on them.
Motherboard ID
private static void FetchMotherboardIdInternal()
{
try
{
ManagementScope scope = new ManagementScope("\\\\" + Environment.MachineName + "\\root\\cimv2");
scope.Connect();
using (ManagementObject wmiClass = new ManagementObject(scope, new ManagementPath("Win32_BaseBoard.Tag=\"Base Board\""), new ObjectGetOptions()))
{
object motherboardIDObj = wmiClass["SerialNumber"];
if (motherboardIDObj != null)
{
string motherboardID = motherboardIDObj.ToString().Trim();
Trace.WriteLine("MotherboardID = " + motherboardID);
if (IsValidMotherBoardID(motherboardID))
{
_motherboardID = motherboardID;
}
}
}
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception ex)
{
Trace.TraceWarning("Failed to read MotherbaordID\r\n" + ex.Message);
}
}
public static bool IsValidMotherBoardID(string value)
{
if (value == null)
return false;
string motherboardID = value.Trim();
return !( motherboardID.Replace(".", "").Replace(" ", "").Replace("\t", "").Trim().Length < 5 ||
motherboardID.ToUpper().Contains("BASE") ||
motherboardID.Contains("2345") ||
motherboardID.ToUpper().StartsWith("TO BE") ||
motherboardID.ToUpper().StartsWith("NONE") ||
motherboardID.ToUpper().StartsWith("N/A") ||
motherboardID.ToUpper().Contains("SERIAL") ||
motherboardID.ToUpper().Contains("OEM") ||
motherboardID.ToUpper().Contains("AAAAA") ||
motherboardID.ToUpper().Contains("ABCDE") ||
motherboardID.ToUpper().Contains("XXXXX") ||
motherboardID.ToUpper().Contains("NOT") ||
motherboardID.ToUpper().StartsWith("00000")
);
}
CPU ID
private static void FetchCpuIdInternal()
{
try
{
using (ManagementClass mc = new ManagementClass("Win32_Processor"))
{
using (ManagementObjectCollection moc = mc.GetInstances())
{
foreach (ManagementObject mo in moc)
{
if (mo.Properties["UniqueId"] != null && mo.Properties["UniqueId"].Value != null)
{
// only return cpuInfo from first CPU
Trace.WriteLine("CPU ID = " + mo.Properties["UniqueId"].Value.ToString());
_cpuID = mo.Properties["UniqueId"].Value.ToString();
}
mo.Dispose();
}
}
}
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception ex)
{
Trace.TraceWarning("Failed to read CPUID\r\n" + ex.Message);
}
}
MAC Adress of first card
private static void FecthMACAddressInternal()
{
try
{
using (ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration"))
{
using (ManagementObjectCollection moc = mc.GetInstances())
{
if (moc != null)
{
foreach (ManagementObject mo in moc)
{
Trace.WriteLine(mo["Index"] + " Mac " + mo["Caption"] + " : " + mo["MacAddress"] + " Enabled " + (bool)mo["IPEnabled"]);
if (string.IsNullOrEmpty(_macAdderss)) // only return MAC Address from first card
{
if ( mo["MacAddress"] != null && mo["IPEnabled"] != null && (bool)mo["IPEnabled"] == true)
{
_macAdderss = mo["MacAddress"].ToString();
}
}
mo.Dispose();
}
}
}
}
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception ex)
{
Trace.TraceWarning("Failed to read DiskID\r\n" + ex.Message);
}
if (_macAdderss != null)
_macAdderss = _macAdderss.Replace(":", "");
}
Drive Serial Number
/// <summary>
/// return Volume Serial Number from hard drive
/// </summary>
/// <param name="strDriveLetter">[optional] Drive letter</param>
/// <returns>[string] VolumeSerialNumber</returns>
public static string GetVolumeSerial(char driveLetter)
{
try
{
using (ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"" + driveLetter + ":\""))
{
if (disk == null)
return null;
disk.Get();
object diskObj = disk["VolumeSerialNumber"];
if (diskObj != null)
return diskObj.ToString();
}
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception ex)
{
Trace.TraceWarning("Failed to read DiskID\r\n" + ex.Message);
}
try
{
uint serialNum, serialNumLength, flags;
StringBuilder volumename = new StringBuilder(256);
StringBuilder fstype = new StringBuilder(256);
bool ok = GetVolumeInformation(driveLetter.ToString() + ":\\", volumename, (uint)volumename.Capacity - 1, out serialNum, out serialNumLength, out flags, fstype, (uint)fstype.Capacity - 1);
if (ok)
{
return string.Format("{0:X4}{1:X4}", serialNum >> 16, serialNum & 0xFFFF);
}
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception ex2)
{
Trace.TraceWarning("Failed to read DiskID\r\n" + ex2.Message);
}
return null;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern bool GetVolumeInformation(string Volume, StringBuilder VolumeName, uint VolumeNameSize, out uint SerialNumber, out uint SerialNumberLength, out uint flags, StringBuilder fs, uint fs_size);

Using System.Management you can extract all Hardware information. with this you can create an ID from this values, meaby a crypted id and save it.
Here is a reference: Link
I use MAC Address, Motherboard id and works fine to me.
I hope this help!

Related

how to get Operating System install patch details with version

Operating system patch
i want to get list of install patch of my operation system with version details in dot net,
i am trying using wmi
string Software = null;
string SoftwareKey = #"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
Software += "\r\nWINDOWS X64 Software\r\n\r\n\r\n ";
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(SoftwareKey))
{
if (rk == null)
{
return Software;
}
foreach (string skName in rk.GetSubKeyNames())
{
using (RegistryKey sk = rk.OpenSubKey(skName))
{
try
{
if (!(sk.GetValue("DisplayName") == null))
{
if (sk.GetValue("InstallLocation") == null)
Software += sk.GetValue("DisplayName") + " - Install path not known \r\n ";
else
Software += sk.GetValue("DisplayName") + " - " + sk.GetValue("InstallLocation") + "\r\n ";
}
}
catch (Exception ex)
{
}
}
}
}
return Software;

C# WinScard.SCardListReaders should list only the connected readers (but it is listing all the past installed reader names which is now not connected)

Please go through my below C# code. I am trying to get the list of Smart Card readers that are now connected to my computer. But this function is returning all the smartcard reader names that was connected in the past (I mean not connected now). I want the list of active (presently) connected readers names only. I am not able to understand where is the issue.
I tried a exe from this website which is written and compiled in C. It is showing only the readers that are connected. I compared the code, but I find no difference. Please help to find a fix.
public static int GetPCSCReaders(out List<string> smartCardReaders, out string errMsg)
{
errMsg = string.Empty;
byte[] readersList = null;
smartCardReaders = new List<string>();
try
{
int hContext = 0;
int ret = SCardEstablishContext(WinSCard.SCARD_SCOPE_USER, 0, 0, ref hContext);
if (ret != 0)
{
errMsg = "WinSCard GetPCSCReader: EstablishContext Error: " + ret.ToString();
return ret;
}
int byteCnt = 0;
ret = WinSCard.SCardListReaders(hContext, null, null, ref byteCnt);
if (ret != SCARD_S_SUCCESS)
{
errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
return ret;
}
readersList = new byte[byteCnt];
ret = WinSCard.SCardListReaders(hContext, null, readersList, ref byteCnt);
if (ret != SCARD_S_SUCCESS)
{
errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
return ret;
}
int indx = 0;
string readerName = string.Empty;
int i = 0;
while (readersList[indx] != 0)
{
while (readersList[indx] != 0)
{
readerName = readerName + (char)readersList[indx++];
}
smartCardReaders.Add(readerName);
i++;
readerName = "";
indx++;
}
}
catch (Exception ex)
{
errMsg = ex.Message;
}
finally
{
readersList = null;
}
return 0;
}
It's hard to answer the question without a smartcard reader in hand, although I developed on these code just 3 months ago.
My previous code is based on this:
https://github.com/nicbedford/CardBrowser/blob/master/PCSC/PCSCReader.cs
It's not working perfectly, you have to detect bugs by yourself. but it exactly helps.
There are different solutions in different windows platforms.
Window 8.1+:
https://code.msdn.microsoft.com/windowsapps/Smart-card-sample-c7d342e0#content
Window 10:
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/SmartCard
https://learn.microsoft.com/en-us/uwp/api/windows.devices.smartcards
Windows 7+:
https://github.com/nicbedford/CardBrowser/tree/master/PCSC
https://github.com/orouit/SmartcardFramework
https://github.com/danm-de/pcsc-sharp/tree/master/src/PCSC
if you meet issue in translating C++ to C#, you can find all functions here:
https://www.pinvoke.net/default.aspx/winscard/SCardTransmit.html
just search the function from top left.
I went through this link, in that page, there is a Tips and Tricks mentioning, "if you invoke SCardListReaders with the hContext parameter set to null, you'll get the list of the installed readers (not the plugged ones !)". As per this, in my code I was having hContext variable as int, I changed it to IntPtr and it made me to list only the readers that are connected. It is Solved and now my code is changed to
public static int GetPCSCReaders(out List<string> smartCardReaders, out string errMsg)
{
errMsg = string.Empty;
smartCardReaders = new List<string>();
IntPtr hContext;
try
{
int ret = SCardEstablishContext(SCARD_SCOPE_USER, IntPtr.Zero, IntPtr.Zero, out hContext);
if (ret != SCARD_S_SUCCESS)
{
errMsg = "WinSCard GetPCSCReader: EstablishContext Error: " + ret.ToString();
return ret;
}
byte[] readersList = null;
uint byteCnt = 0;
ret = SCardListReaders(hContext, null, null, ref byteCnt);
if (ret != SCARD_S_SUCCESS)
{
errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
return ret;
}
readersList = new byte[byteCnt];
ret = SCardListReaders(hContext, null, readersList, ref byteCnt);
if (ret != SCARD_S_SUCCESS)
{
errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
return ret;
}
int indx = 0;
string readerName = string.Empty;
int i = 0;
while (readersList[indx] != 0)
{
while (readersList[indx] != 0)
{
readerName = readerName + (char)readersList[indx++];
}
smartCardReaders.Add(readerName);
i++;
readerName = "";
indx++;
}
}
catch (Exception ex)
{
errMsg = ex.Message;
}
finally
{
}
return 0;
}

Encode and Decode Mac address from UUID using C#

I need to generate UUID for my Machine Mac address. Also i want extract the mac address from UUID.
I know we can use below two methods for encoding and decoding. But it will generate the encrypted string only not UUID.
Encode:
System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(plainTextBytes));
Decode:
System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(base64EncodedData));
But for my requirement i want to generate(encode) the UUID and extract(decode) the mac address . How to do this in C# code?
You can get the MAC address using the following code.
From our tests it will return null on about 1.3% of machines (probably some form of virtual machine or something very locked down).
MAC Address of first IP enabled device
public static string GetMACAddress()
{
try
{
using (ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration"))
{
using (ManagementObjectCollection moc = mc.GetInstances())
{
if (moc != null)
{
foreach (ManagementObject mo in moc)
{
try
{
Trace.WriteLine(mo["Index"] + " Mac " + mo["Caption"] + " : " + mo["MacAddress"] + " Enabled " + (bool)mo["IPEnabled"]);
if (mo["MacAddress"] != null && mo["IPEnabled"] != null && (bool)mo["IPEnabled"] == true)
{
return mo["MacAddress"].ToString();
}
}
finally
{
mo.Dispose();
}
}
}
}
}
}
catch (Exception ex)
{
Trace.TraceWarning("Failed to read DiskID\r\n" + ex.Message);
}
return null;
}

How to verify if remote computer is available?

I'm writing a part of a program that shall copy a batch of files from the current computer to a defined list of computers.
If these computers are not available, the code will hang for a long time trying to access them. Is there any functionallity in C# to check if the machine is available and then skip if it's not?
MFWs = File.ReadAllLines(GuiManager.MyConfigManagerConfig.MachinesList);
foreach (string MFW in MFWs)
{
if (MFW != System.Environment.MachineName)
{
String target = #"\\" + MFW + #"\D\IbSi\config\" + Path.GetFileName(ConfigFile);
String backup = #"\\" + MFW + #"\D\IbSi\userdata\" + Path.GetFileName(ConfigFile);
try
{
File.Copy(source, target, true);
File.Copy(source, backup, true);
}
catch (Exception ex)
{
Manager.SendMessage("Failed to copy " + Path.GetFileName(ConfigFile) + " to " + MFW + "\n" + ex.Message);
}
}
}
You could ping the computer before starting the copy (taken from this answer):
using System.Net.NetworkInformation;
public static bool IsHostAvailable(string nameOrAddress)
{
bool pingable = false;
Ping pinger = new Ping();
try
{
PingReply reply = pinger.Send(nameOrAddress);
pingable = reply.Status == IPStatus.Success;
}
catch (PingException)
{
// Discard PingExceptions and return false;
}
return pingable;
}
As noted in the comments you need to make sure the firewall on the servers is open for pings (ICMP echo requests)

Win32_EncryptableVolume Device loop in C#

I'm trying to build a loop for each device that may be connected to a Win7 and up machine using BitLocker. It hasn't been an issue in the past since we've been using TPMs, but now we're trying USB keys to reduce costs. My old code only showed the last devices encryption status which ended up being the USB drive. So I'd like to create a loop that lists each drive and it's encryption status.
My goal is to create an array with each drives status in it. The problem I'm running in to is identifying how many items are actually found as a result of searcher.Get() (which I believe should be the encrArr array below), so I'm going with 2 for now for the hard drive and USB drive.
The code below doesn't show any errors while writing it, but it crashes when I try to run it ("Exception has been thrown by the target of an invocation.").
public string[] getBitLockerArr()
{
string[] encrArr = new string[2];
encrArr[0] = "Protection Off, Fully Decrypted, 0% encrypted";
encrArr[1] = "Protection Off, Fully Decrypted, 0% encrypted";
ManagementObjectSearcher searcher = new
ManagementObjectSearcher("root\\cimv2\\Security\\MicrosoftVolumeEncryption", "SELECT * FROM Win32_EncryptableVolume");
int i = 0;
foreach (ManagementObject wmi in searcher.Get())
{
try
{
string[] bitLockerArr = new string[3];
bitLockerArr[0] = "Unknown";
bitLockerArr[1] = "Unknown";
bitLockerArr[2] = "Unknown";
StringBuilder bitLocker = new StringBuilder();
ManagementObject classInstance =
new ManagementObject("root\\cimv2\\Security\\MicrosoftVolumeEncryption", "Win32_EncryptableVolume.DeviceID='" + wmi["DeviceID"] + "'", null);
ManagementBaseObject statProtection = classInstance.InvokeMethod("GetProtectionStatus", null, null);
ManagementBaseObject statConversion = classInstance.InvokeMethod("GetConversionStatus", null, null);
if (statProtection["ProtectionStatus"] != null) { bitLockerArr[0] = statProtection["ProtectionStatus"].ToString(); }
if (statConversion["ConversionStatus"] != null) { bitLockerArr[1] = statConversion["ConversionStatus"].ToString(); }
if (statConversion["EncryptionPercentage"] != null) { bitLockerArr[2] = statConversion["EncryptionPercentage"].ToString(); }
// BitLocker Protection Status
string blProtStat = bitLockerArr[0];
if (blProtStat == "0") { blProtStat = "Protection Off"; }
else if (blProtStat == "1") { blProtStat = "Protection On"; }
// BitLocker Conversion Statuses
string blConvStat = bitLockerArr[1];
if (blConvStat == "0") { blConvStat = ", Fully Decrypted"; }
else if (blConvStat == "1") { blConvStat = ", Fully Encrypted"; }
else if (blConvStat == "2") { blConvStat = ", Encryption In Progress"; }
else if (blConvStat == "3") { blConvStat = ", Decryption In Progress"; }
else if (blConvStat == "4") { blConvStat = ", Encryption Paused"; }
else if (blConvStat == "5") { blConvStat = ", Decryption Paused"; }
// BitLocker Encryption Status
string blEncStat = ", " + bitLockerArr[2] + "% encrypted";
encrArr[i] = wmi["DriveLetter"] + " " + blProtStat + blConvStat + blEncStat + ", " + wmi["DeviceID"];
i = i + 1;
}
catch { }
}
return encrArr;
}

Categories