Determine from which location an application was being started - c#
Is there any possibility to determine how a c# application was being started?
In my case I want to check if this application (wpf) is being started by a shortcut located in a specific folder.
So, there are two ways to open my application
using direct shortcut
starting another application which is like an update manager to keep my application up to date. After checking, it starts my application with Process.Start()
And I want to ensure that the application is only able to be started with the update manager.
A trick you could use is to check the parent's PID, and then get some of the parent's process information.
If the parent's process name is something like "explorer.exe" then the application was started from the shortcut or directly by double-clicking it on explorer.
Otherwise, it was started from another application: it could be your updater application, it could also be another application with the same name as your updater application...
This means you have to re-think how deep you want to go for such a solution, and how deep do you want security control. You could pass arguments from your updater to your main application, or implement some inter-process communication with token exchanges... it is impossible to make a 100% secure system.
As someone commented above, this seems like a XY problem... or maybe not. Maybe it is just a security concern. It's recommended to revise what exactly are you aiming for this software.
In case you need sample code for retrieving process information in .NET (by using System.Management), then just give a try to the code listed below. All you have to do is to place it in a console application project named 'Updater', and correctly set the path to your main application in the code.
If you play a little bit with this example by starting and closing YourApplication.exe in different situations, then you should be able to see an output like this:
Parent process 'Updater.exe' [PID=5472]
Parent process 'explorer.exe' [PID=12052]
The code below was tested on VS2017 .Net 4.6.1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
class Program
{
static void Main(string[] args)
{
Process.Start(new ProcessStartInfo()
{
FileName = "YourApplication.exe" // path to your application
});
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
Process process = Process.GetProcessesByName("YourApplication").FirstOrDefault(); // your application's process name
if (process == null)
{
Console.WriteLine($"Process is not running...");
continue;
}
ProcessManager pm = ProcessManager.FromLocalMachine();
var processProperties = pm.GetProcessProperties(process.Id);
int parentProcessId = Convert.ToInt32(processProperties[EProcessProperty.ParentProcessId]);
try
{
var parentProcessProperties = pm.GetProcessProperties(parentProcessId);
string parentProcessName = parentProcessProperties[EProcessProperty.Name].ToString();
Console.WriteLine($"Parent process '{parentProcessName ?? "Unknown"}' [PID={parentProcessId}]");
Console.WriteLine("---------------------------------");
}
catch { Console.WriteLine("Parent process information not found."); }
}
}
}
public class ProcessConnection
{
internal ManagementScope ManagementScope { get; }
internal ProcessConnection(string machineName, string user = null, string password = null, string domain = null)
{
ManagementScope = new ManagementScope
{
Path = new ManagementPath(#"\\" + machineName + #"\root\CIMV2"),
Options = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.Default,
EnablePrivileges = true,
Username = user == null ? null : (string.IsNullOrWhiteSpace(domain) ? user : $"{domain}\\{user}"),
Password = user == null ? null : password,
},
};
ManagementScope.Connect();
}
}
public class ProcessManager
{
public static ProcessManager FromLocalMachine() => new ProcessManager()
{
Machine = Environment.MachineName,
};
public static ProcessManager FromRemoteMachine(string machine, string user = null, string password = null, string domain = null) => new ProcessManager()
{
Machine = machine,
User = user,
Password = password,
Domain = domain,
};
private ProcessManager() { }
public string Machine { get; private set; }
public string User { get; private set; }
public string Password { get; private set; }
public string Domain { get; private set; }
private ProcessConnection Connection { get; set; }
private ManagementScope ManagementScope => Connection == null ? (Connection = new ProcessConnection(Machine, User, Password, Domain)).ManagementScope : Connection.ManagementScope;
public EProcessStartStatus StartProcess(string processPath)
{
ManagementClass mc = new ManagementClass($"\\\\{Machine}\\root\\CIMV2", "Win32_Process", null);
ManagementBaseObject process = mc.GetMethodParameters("Create");
process["CommandLine"] = processPath;
ManagementBaseObject createCode = mc.InvokeMethod("Create", process, null);
string createCodeStr = createCode["ReturnValue"].ToString();
return (EProcessStartStatus)Convert.ToInt32(createCodeStr);
}
public bool KillProcess(string processName)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public bool KillProcess(int processId)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public void SetProcessPriority(string processName, EProcessPriority priority)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject managementObject in managementObjectSearcher.Get())
{
ManagementBaseObject methodParams = managementObject.GetMethodParameters("SetPriority");
methodParams["Priority"] = priority;
managementObject.InvokeMethod("SetPriority", methodParams, null);
}
}
public string GetProcessOwner(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwner");
ManagementBaseObject owner = mo.InvokeMethod("GetOwner", null, null);
return owner["User"].ToString();
}
return null;
}
public string GetProcessOwnerSID(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwnerSid");
ManagementBaseObject OwnerSid = mo.InvokeMethod("GetOwnerSid", null, null);
return OwnerSid["Sid"].ToString();
}
return null;
}
public IList<int> GetRunningProcesses()
{
IList<int> processes = new List<int>();
SelectQuery query = new SelectQuery("SELECT * FROM Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) processes.Add(int.Parse(mo["ProcessId"].ToString()));
return processes;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(int processId)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IList<int> GetProcessessFromExecutablePath(string executablePath)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ExecutablePath = '{executablePath.Replace("\\", "\\\\")}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
return searcher.Get().Cast<ManagementObject>().Select(mo => Convert.ToInt32(mo["ProcessId"])).ToList();
}
}
public enum EProcessPriority : uint
{
IDLE = 0x40,
BELOW_NORMAL = 0x4000,
NORMAL = 0x20,
ABOVE_NORMAL = 0x8000,
HIGH_PRIORITY = 0x80,
REALTIME = 0x100
}
public enum EProcessStartStatus
{
Success = 0,
AccessDenied = 2,
NoPermissions = 3,
Unknown = 8,
FileNotFound = 9,
Invalid = 21,
}
public enum EProcessProperty
{
Caption,
CommandLine,
CreationClassName,
CreationDate,
CSCreationClassName,
CSName,
Description,
ExecutablePath,
ExecutionState,
Handle,
HandleCount,
InstallDate,
KernelModeTime,
MaximumWorkingSetSize,
MinimumWorkingSetSize,
Name,
OSCreationClassName,
OSName,
OtherOperationCount,
OtherTransferCount,
PageFaults,
PageFileUsage,
ParentProcessId,
PeakPageFileUsage,
PeakVirtualSize,
PeakWorkingSetSize,
Priority,
PrivatePageCount,
ProcessId,
QuotaNonPagedPoolUsage,
QuotaPagedPoolUsage,
QuotaPeakNonPagedPoolUsage,
QuotaPeakPagedPoolUsage,
ReadOperationCount,
ReadTransferCount,
SessionId,
Status,
TerminationDate,
ThreadCount,
UserModeTime,
VirtualSize,
WindowsVersion,
WorkingSetSize,
WriteOperationCount,
WriteTransferCount,
}
If there are only 2 ways of starting your app, the second method should pass a parameter (a GUID?) to Process.Start() - generated by your updater app.
Maybe devise some kind of algorithm that allows the app to start only with the token.
From what I know this is impossible in the way you would like it to be but there's one trick which you can use. Firstly change your WPF application's entry method to get the command line arguments, and ( for example ) use -u argument to distinct from where the application was started. Then after -u you can pass a HWND or a process ID that matches your updater. Of course you have to then check if that application is running and if it's your updater.
example :
// updated process start
ProcessStartInfo psi = new ProcessStartInfo("your/WPF/application.exe");
psi.Arguments = "-u " + Process.GetCurrentProcess().Id;
// fill up rest of the properties you need
Process.Start(psi);
// wpf application's entry point
void Main(string[] args)
{
string updaterProcessIdstr = string.Empty;
for (int i = 0; i < args.Length; i++)
{
if(args[i] == "-u")
{
updaterProcessIdstr = args[i + 1];
i++;
}
}
int pid = int.Parse(updaterProcessIdstr);
Process updaterProcess = Process.GetProcessById(pid);
// do some validation here
// send something to stdin and read from stdout
// to determine if it was started from that updater.
}
Related
C#, Process Viewer, which is service vs desktop app
I'm not writing a process viewer, but need somewhat the same concept. I can do List<Process> allProcesses = Process.GetProcesses().ToList(); Question: How can I tell which process is a normal process and which is a windows service? I've dug through the properties of Process and not finding a flag of any sort.
private bool IsService(Process p, out string serviceName) { bool retVal = false; serviceName = ""; string query = $"SELECT Name FROM Win32_Service WHERE ProcessId={p.Id}"; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); foreach (ManagementObject obj in searcher.Get()) { serviceName = obj["Name"].ToString(); retVal = true; break; } return retVal; }
Process.StartInfo.Username is empty
I start a Process by Process app = new Process(); app.StartInfo.UseShellExecute = false; app.StartInfo.FileName = path; app.StartInfo.Domain = "Domain"; app.StartInfo.UserName = "userName"; string password = "Password"; System.Security.SecureString ssPwd = new System.Security.SecureString(); for (int x = 0; x < password.Length; x++) { ssPwd.AppendChar(password[x]); } password = ""; app.StartInfo.Password = ssPwd; app.Start(); Then I confirm it is running by: private bool IsRunning(string name) { Process[] processlist = Process.GetProcesses(); if (Process.GetProcessesByName(name).Length > 0) { string user = Process.GetProcessesByName(name)[0].StartInfo.UserName; log.Debug("Process " + name + " is running by : " + user); return true; } else { return false; } } I get back true and find the process but the UserName is empty. Why is that? I also found some code to get the Owner of the Process but when I use this the Owner is also empty. public string GetProcessOwner(int processId) { string query = "SELECT * FROM Win32_Process WHERE ProcessID = " + processId; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); foreach (ManagementObject obj in processList) { string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { // return DOMAIN\user return argList[1] + "\\" + argList[0]; } } return "NO OWNER"; } Please can you explain me why this is so?
This is by design; when requesting information about a Process via eg. GetProcessesByName the UserName doesn't get retrieved/resolved. GetProcessByName internally retrieves its info via the code below, constructing Process instances from the obtained ProcesInfo data. public static Process[] GetProcesses(string machineName) { bool isRemoteMachine = ProcessManager.IsRemoteMachine(machineName); ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(machineName); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) { ProcessInfo processInfo = processInfos[i]; processes[i] = new Process(machineName, isRemoteMachine, processInfo.processId, processInfo); } return processes; } A ProcessInfo instance doesn't contain any user/owner information. internal class ProcessInfo { public ArrayList threadInfoList = new ArrayList(); public int basePriority; public string processName; public int processId; public int handleCount; public long poolPagedBytes; public long poolNonpagedBytes; public long virtualBytes; public long virtualBytesPeak; public long workingSetPeak; public long workingSet; public long pageFileBytesPeak; public long pageFileBytes; public long privateBytes; public int mainModuleId; public int sessionId; } The private constructor of the Process class accepts this ProcessInfo. Because no ProcessStartInfo has been set, it instantiates one on retrieval, having an empty UserName. public string UserName { get { if( userName == null) { return string.Empty; } else { return userName; } } set { userName = value; } } About the GetProcessOwner code; this results from the answer to the How do I determine the owner of a process in C#? question. This is rather an other WMI related topic; not receiving any owner info might have to do with permissions as suggested in the comments. For me, "it works on my machine" ... Better start a separate question for this one.
I tried with solution using WinAPIs You would get "NO OWNER" when the application you are trying to get the owner, is not run as admin Please check by running your application as Administrator
How to Change DNS with C# on Windows 10
I'm trying to change the DNS on Windows 10 through VB.NET. I have code that works on Windows 7, however it does not work on Windows 10. Here is my code for Windows 7 that changes the DNS: ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration"); ManagementObjectCollection moc = mc.GetInstances(); foreach (ManagementObject mo in moc) { if ((bool)mo["IPEnabled"]) { ManagementBaseObject objdns = mo.GetMethodParameters("SetDNSServerSearchOrder"); if (objdns != null) { string[] s = { "192.168.XX.X", "XXX.XX.X.XX" }; objdns["DNSServerSearchOrder"] = s; mo.InvokeMethod("SetDNSServerSearchOrder", objdns, null); My question is, how do I get this to work on Windows 10 OS?
First you need to get the NetworkInterface you want to set/unset DNS I've tested this code on the latest version of Windows 10 and it works like a charm! Here is the code to find the active Ethernet or Wifi network (Not 100% accurate but useful in most cases) public static NetworkInterface GetActiveEthernetOrWifiNetworkInterface() { var Nic = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault( a => a.OperationalStatus == OperationalStatus.Up && (a.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || a.NetworkInterfaceType == NetworkInterfaceType.Ethernet) && a.GetIPProperties().GatewayAddresses.Any(g => g.Address.AddressFamily.ToString() == "InterNetwork")); return Nic; } SetDNS public static void SetDNS(string DnsString) { string[] Dns = { DnsString }; var CurrentInterface = GetActiveEthernetOrWifiNetworkInterface(); if (CurrentInterface == null) return; ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration"); ManagementObjectCollection objMOC = objMC.GetInstances(); foreach (ManagementObject objMO in objMOC) { if ((bool)objMO["IPEnabled"]) { if (objMO["Description"].ToString().Equals(CurrentInterface.Description)) { ManagementBaseObject objdns = objMO.GetMethodParameters("SetDNSServerSearchOrder"); if (objdns != null) { objdns["DNSServerSearchOrder"] = Dns; objMO.InvokeMethod("SetDNSServerSearchOrder", objdns, null); } } } } } UnsetDNS public static void UnsetDNS() { var CurrentInterface = GetActiveEthernetOrWifiNetworkInterface(); if (CurrentInterface == null) return; ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration"); ManagementObjectCollection objMOC = objMC.GetInstances(); foreach (ManagementObject objMO in objMOC) { if ((bool)objMO["IPEnabled"]) { if (objMO["Description"].ToString().Equals(CurrentInterface.Description)) { ManagementBaseObject objdns = objMO.GetMethodParameters("SetDNSServerSearchOrder"); if (objdns != null) { objdns["DNSServerSearchOrder"] = null; objMO.InvokeMethod("SetDNSServerSearchOrder", objdns, null); } } } } } Usage SetDNS("127.0.0.1");
Combining multiple solutions I found that the following code is working great for Windows 10 and 8.1 (others not tested, but should work as well): public static void setDNS(string NIC, string DNS) { ConnectionOptions options = PrepareOptions(); ManagementScope scope = PrepareScope(Environment.MachineName, options, #"\root\CIMV2"); ManagementPath managementPath = new ManagementPath("Win32_NetworkAdapterConfiguration"); ObjectGetOptions objectGetOptions = new ObjectGetOptions(); ManagementClass mc = new ManagementClass(scope, managementPath, objectGetOptions); ManagementObjectCollection moc = mc.GetInstances(); foreach (ManagementObject mo in moc) { if ((bool)mo["IPEnabled"]) { if (mo["Caption"].ToString().Contains(NIC)) { try { ManagementBaseObject newDNS = mo.GetMethodParameters("SetDNSServerSearchOrder"); newDNS["DNSServerSearchOrder"] = DNS.Split(','); ManagementBaseObject setDNS = mo.InvokeMethod("SetDNSServerSearchOrder", newDNS, null); } catch (Exception e) { Console.WriteLine(e.ToString()); Console.ReadKey(); throw; } } } } } The application needs to run with elevated permissions (in my case I'm starting an elevated process running an .exe): private void callSwapDNS(string NIC, string DNS) { const int ERROR_CANCELLED = 1223; //The operation was canceled by the user. ProcessStartInfo info = new ProcessStartInfo(#"swap.exe"); string wrapped = string.Format(#"""{0}"" ""{1}""", NIC, DNS); info.Arguments = wrapped; info.UseShellExecute = true; info.Verb = "runas"; info.WindowStyle = ProcessWindowStyle.Hidden; try { Process.Start(info); Thread.Sleep(500); } catch (Win32Exception ex) { if (ex.NativeErrorCode == ERROR_CANCELLED) MessageBox.Show("Why you no select Yes?"); else throw; } } Using mo["Caption"].ToString().Contains(NIC) doesn't work for Windows 10 as the WMI query returns the NIC-Name leading with [000000] [000000] Intel(R) 82574L Gigabit Network Connection on my Windows 10 machine. Credit to the following answers: [WMI not working after upgrading to Windows 10 WMI not working after upgrading to Windows 10 How can you change Network settings (IP Address, DNS, WINS, Host Name) with code in C# and the answers to this question.
With Windows 10 you may need authentication first. Pass a ConnectionOptions instance to a ManagementScope constructor, defining your Authentication and Impersonation properties. Try this: // Method to prepare the WMI query connection options. public static ConnectionOptions PrepareOptions ( ) { ConnectionOptions options = new ConnectionOptions ( ); options . Impersonation = ImpersonationLevel . Impersonate; options . Authentication = AuthenticationLevel . Default; options . EnablePrivileges = true; return options; } // Method to prepare WMI query management scope. public static ManagementScope PrepareScope ( string machineName , ConnectionOptions options , string path ) { ManagementScope scope = new ManagementScope ( ); scope . Path = new ManagementPath ( #"\\" + machineName + path ); scope . Options = options; scope . Connect ( ); return scope; } // Set DNS. ConnectionOptions options = PrepareOptions ( ); ManagementScope scope = PrepareScope ( Environment . MachineName , options , #"\root\CIMV2" ); ManagementClass mc = new ManagementClass(scope, "Win32_NetworkAdapterConfiguration"); ManagementObjectCollection moc = mc.GetInstances(); foreach (ManagementObject mo in moc) { if ((bool)mo["IPEnabled"]) { ManagementBaseObject objdns = mo.GetMethodParameters("SetDNSServerSearchOrder"); if (objdns != null) { string[] s = { "192.168.XX.X", "XXX.XX.X.XX" }; objdns["DNSServerSearchOrder"] = s; mo.InvokeMethod("SetDNSServerSearchOrder", objdns, null); Based on this answer: WMI not working after upgrading to Windows 10
This is the code I use to do this and it works: /// <summary> /// Set's the DNS Server of the local machine /// </summary> /// <param name="NIC">NIC address</param> /// <param name="DNS">DNS server address</param> /// <remarks>Requires a reference to the System.Management namespace</remarks> public void setDNS(string NIC, string DNS) { ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration"); ManagementObjectCollection objMOC = objMC.GetInstances(); foreach (ManagementObject objMO in objMOC) { if ((bool)objMO["IPEnabled"]) { // if you are using the System.Net.NetworkInformation.NetworkInterface you'll need to change this line to if (objMO["Caption"].ToString().Contains(NIC)) and pass in the Description property instead of the name if (objMO["Caption"].Equals(NIC)) { try { ManagementBaseObject newDNS = objMO.GetMethodParameters("SetDNSServerSearchOrder"); newDNS["DNSServerSearchOrder"] = DNS.Split(','); ManagementBaseObject setDNS = objMO.InvokeMethod("SetDNSServerSearchOrder", newDNS, null); } catch (Exception) { throw; } } } } } Hope it helps...
How to check Windows license status in C#?
I want my program to check if Windows 10 has been activated I have the following code public static bool IsWindowsActivated() { bool activated = true; ManagementScope scope = new ManagementScope(#"\\" + System.Environment.MachineName + #"\root\cimv2"); scope.Connect(); SelectQuery searchQuery = new SelectQuery("SELECT * FROM Win32_WindowsProductActivation"); ManagementObjectSearcher searcherObj = new ManagementObjectSearcher(scope, searchQuery); using (ManagementObjectCollection obj = searcherObj.Get()) { foreach (ManagementObject o in obj) { activated = ((int)o["ActivationRequired"] == 0) ? true : false; } } return activated; } when trying to use this code, the debugger complains Invalid class, which I have no idea what it is what should I do to fix this? or is there any other way to check the license status of Windows?
The WMI class Win32_WindowsProductActivation is only supported on windows XP. For windows 10 you need to use SoftwareLicensingProduct public static bool IsWindowsActivated() { ManagementScope scope = new ManagementScope(#"\\" + System.Environment.MachineName + #"\root\cimv2"); scope.Connect(); SelectQuery searchQuery = new SelectQuery("SELECT * FROM SoftwareLicensingProduct WHERE ApplicationID = '55c92734-d682-4d71-983e-d6ec3f16059f' and LicenseStatus = 1"); ManagementObjectSearcher searcherObj = new ManagementObjectSearcher(scope, searchQuery); using (ManagementObjectCollection obj = searcherObj.Get()) { return obj.Count > 0; } }
How to get motherboard ID without receiving empty strings?
I tried many things: //public static string GetMotherBoardID() //{ // string mbInfo = String.Empty; // //Get motherboard's serial number // ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_BaseBoard"); // foreach (ManagementObject mo in mbs.Get()) // mbInfo += mo["SerialNumber"].ToString(); // return mbInfo; //} //public static string GetMotherBoardID() //{ // string mbInfo = String.Empty; // ManagementScope scope = new ManagementScope("\\\\" + Environment.MachineName + "\\root\\cimv2"); // scope.Connect(); // ManagementObject wmiClass = new ManagementObject(scope, new ManagementPath("Win32_BaseBoard.Tag=\"Base Board\""), new ObjectGetOptions()); // foreach (PropertyData propData in wmiClass.Properties) // { // if (propData.Name == "SerialNumber") // mbInfo = String.Format("{0,-25}{1}", propData.Name, Convert.ToString(propData.Value)); // } // return mbInfo; //} public static string GetMotherBoardID() { string mbInfo = String.Empty; ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_BaseBoard"); ManagementObjectCollection moc = mbs.Get(); ManagementObjectCollection.ManagementObjectEnumerator itr = moc.GetEnumerator(); itr.MoveNext(); mbInfo = itr.Current.Properties["SerialNumber"].Value.ToString(); var enumerator = itr.Current.Properties.GetEnumerator(); if (string.IsNullOrEmpty(mbInfo)) mbInfo = "0"; return mbInfo; } This all gives empty string on my PC, but the correct ID on the laptop. Some other person also reporting on two PCs is empty motherboard ID. The result of: public static string GetMotherBoardID() { string mbInfo = String.Empty; ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_BaseBoard"); ManagementObjectCollection moc = mbs.Get(); ManagementObjectCollection.ManagementObjectEnumerator itr = moc.GetEnumerator(); itr.MoveNext(); mbInfo = itr.Current.Properties["SerialNumber"].Value.ToString(); var enumerator = itr.Current.Properties.GetEnumerator(); string properties = ""; while (enumerator.MoveNext()) { properties += "[" + enumerator.Current.Name + "][" + (enumerator.Current.Value != null ? enumerator.Current.Value.ToString() : "NULL") + "]\n"; } if (string.IsNullOrEmpty(mbInfo)) mbInfo = "0"; return mbInfo; } [Caption][Основная плата] [ConfigOptions][NULL] [CreationClassName][Win32_BaseBoard] [Depth][NULL] [Description][Основная плата] [Height][NULL] [HostingBoard][True] [HotSwappable][False] [InstallDate][NULL] [Manufacturer][Gigabyte Technology Co., Ltd.] [Model][NULL] [Name][Основная плата] [OtherIdentifyingInfo][NULL] [PartNumber][NULL] [PoweredOn][True] [Product][H55M-S2H] [Removable][False] [Replaceable][True] [RequirementsDescription][NULL] [RequiresDaughterBoard][False] [SerialNumber][ ] [SKU][NULL] [SlotLayout][NULL] [SpecialRequirements][NULL] [Status][OK] [Tag][Base Board] [Version][x.x] [Weight][NULL] [Width][NULL] Maybe c# is bad for retrieving such things? I hope for solution on C/C++ or working solution on C#
Some motherboards simply don't have ID. It set to empty string. So, if someone need to use motherboard unique thing for licensing purposes they should receive motherboard UUID.
Personally, I'd recommend using this particular Open Source hardware monitor library (you'll need the source). You can use it for hardware identification. Open Hardware Monitor
There is also a NuGet package called DeviceID. However, you will need to include their DLL with your package, but is a great fast, simple solution. Here a usage example: /* Depends on https://www.nuget.org/packages/DeviceId/ Install-Package DeviceId - Version 5.2.0*/ /* Using AddMacAddress(true, true) to exclude both virtual and wireless network adapters. */ readonly string MachineSupportID = new DeviceIdBuilder() .AddMacAddress(true, true) .AddMotherboardSerialNumber() .AddProcessorId() .AddSystemDriveSerialNumber() .ToString(); May the force be with you.