I need to retrieve the name of drive where Windows is installed.
Best way I found to do it is via registry, since WMI is very slow for this specific query.
string diskdrive = Registry.GetValue(#"HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0", "Identifier", null);
Which returns : INTEL SSDSCKKF512H6 LBF
While this works perfect form my system, "Target Id" seems to have different digit identifier for other system. how would I go about to detect the specific target ID (maybe detect it by using part of the registry subkey string, somehow).
Not even sure this will do the job for other type of disks (Nvme or IDE).
If there is a better way to do this without WMi query.
Thanks in advance
Found something from CMD:
REG QUERY "HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0" /v Identifier /s
This searches for the registry key named Identifier within Target Id 0
Okay, then try:
This optimized version executes in ~65 ms on my system. That should be good enough.
//ManagementObject sys = new ManagementObject("Win32_OperatingSystem=#");
//string systemDrive = sys["SystemDrive"].ToString();
//Console.WriteLine("System Drive is {0}", systemDrive);
string strQuery = "ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\""
+ System.IO.Path.GetPathRoot(Environment.SystemDirectory).Replace("\\", "")
+ "\"} WHERE AssocClass = Win32_LogicalDiskToPartition";
RelatedObjectQuery relquery = new RelatedObjectQuery(strQuery);
ManagementObjectSearcher search = new ManagementObjectSearcher(relquery);
UInt32 ndx = 0;
foreach (var diskPartition in search.Get())
{
ndx = (uint)diskPartition["DiskIndex"];
Console.WriteLine("Disk Index of System Drive is {0}, Disk Partition is {1}", ndx, diskPartition["DeviceID"]);
}
SelectQuery diskQuery = new SelectQuery(string.Format("SELECT * FROM Win32_DiskDrive WHERE Index={0}", ndx));
ManagementObjectSearcher diskSearch = new ManagementObjectSearcher(diskQuery);
foreach (var disk in diskSearch.Get())
{
Console.WriteLine("Caption is {0}", disk["Caption"]);
Console.WriteLine("Serial Number is {0}", disk["SerialNumber"]);
Console.WriteLine("Model is {0}", disk["Model"]);
Console.WriteLine("InterfaceType is {0}", disk["InterfaceType"]);
}
Related
We are working on a programm to configure some NICs.
We have to change IP Adresses, Subnetmask and the MTU.
Everything went well except the MTU Statement:
public void SetMTU()
{
ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection objMOC = objMC.GetInstances();
foreach (ManagementObject objMO in objMOC)
{
if (networkadapterID == (String)objMO["SettingID"])
{
ManagementBaseObject setMTU;
ManagementBaseObject newMTU = objMO.GetMethodParameters("SetMTU");
Int32 test = 9216;
newMTU["MTU"] = test;
setMTU = objMO.InvokeMethod("SetMTU", newMTU, null);
}
}
}
The correct NIC ID is given. Other WMI Operations succeed but we stuck on that one with error Message:
System.Management.ManagementException: "Die Methode ist ungültig. "
(System.Management.ManagementException: "The Method is invalid.")
We have also tried to use "test" as string or uint32 (because the microsoft docs says it's an uint32),also:
newMTU["MTU"] = new (u)int[] { MTU };
but it doesnt work either.
Meanwhile we don't have any ideas how to fix the problem.
I am grateful for every idea.
Thanks for your help and have a good day,
Alex
Edit:
Code to read the MTU should be (you have to tell this part a NetworkID so you don't read the Value of every NIC, you find this in your registry, but you should be able to delete the if part):
ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection objMOC = objMC.GetInstances();
foreach (ManagementObject objMO in objMOC)
{
if (networkadapterID == (String)objMO["SettingID"])
{
MessageBox.Show(Convert.ToString(objMO["MTU"]) + ": " + Convert.ToString(objMO["SettingID"]));
}
}
So far we didn't get the problem solved but we now check if the OS is Windows 10 and we will start a PowerShell task with this command:
Get-NetAdapterAdvancedProperty -Name 'NICName' -DisplayName 'Jumbo-Rahmen' | Set-NetAdapterAdvancedProperty -RegistryValue 'MTUsize';
Jumbo-Rahmen should be JumboPacket on an English OS
If the OS is not Windows 10 the User will be asked to change the MTU manually
I try to find a unique ID, which will be the same as the virtual machine and the main machine.
I tried using a monitor ID, bios number, but they can repeat for different end users.
using (ManagementObjectSearcher monitorSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_DesktopMonitor"))
{
foreach (ManagementObject monitor in monitorSearcher.Get())
{
String MonitorName = monitor["Name"].ToString();
String MonitorId = monitor["DeviceId"].ToString();
Console.WriteLine("Monitor name: {0}", MonitorName);
Console.WriteLine("Monitor id: {0}", MonitorId);
}
}
ManagementClass managementClass = new ManagementClass("Win32_BIOS");
ManagementObjectCollection instances = managementClass.GetInstances();
foreach (ManagementBaseObject instance in instances)
{
string version = instance.Properties["SMBIOSBIOSVersion"].Value.ToString();
Console.WriteLine("The version is :" + version.ToString());
}
I read a lot and browsed various topics and forums, but nowhere can I find information or is it possible at all? Maybe there is at least one serial number which will be repeated on the main machine as well as on the virtual one?
How do I determine the owner of a process in C#?
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";
}
I detailed studied and implemented the code as given above. This code works fine but only gets the owner names of those processes which are 32 bits. The method return "no owner" for 64 bits processes.
Please help me, how I can get the processes owner names for both 32 bit processes and 64 bit processes.
No, that code works "fine". It also works when your code is 32bit but the target process is 64bit, so no issue here as well.
Possible reasons why you could get "NO OWNER":
You are trying to get the owner for which you have no permission (e.g. you are running as non-privileged user, but trying to get the owner of a privileged one).
You are trying to get the owner of a pseudo process (e.g. "System", with PID 4, or "System Idle Process" with PID 0).
BTW, also services have owners (regarding #weismat comment).
I am working on an installation program for one of my company's product. The product can be installed multiple times and each installation represents a separate windows service. When users upgrade or reinstall the program, I would like to look up the services running, find the services that belong to the product, and then find the executable file and its path for that service. Then use that information to find which one of the services the user wishes to upgrade/replace/install/etc. In my code example below, I see the service name, description, etc, but don't see the actual filename or path. Could someone please tell me what I'm missing? Thank you in advance!
The code I have is as follows:
ServiceController[] scServices;
scServices = ServiceController.GetServices();
foreach (ServiceController scTemp in scServices)
{
if (scTemp.ServiceName == "ExampleServiceName")
{
Console.WriteLine();
Console.WriteLine(" Service : {0}", scTemp.ServiceName);
Console.WriteLine(" Display name: {0}", scTemp.DisplayName);
ManagementObject wmiService;
wmiService = new ManagementObject("Win32_Service.Name='" + scTemp.ServiceName + "'");
wmiService.Get();
Console.WriteLine(" Start name: {0}", wmiService["StartName"]);
Console.WriteLine(" Description: {0}", wmiService["Description"]);
}
}
I might be wrong but the ServiceController class doesn't provide that information directly.
So as suggested by Gene - you will have to use the registry or WMI.
For an example of how to use the registry, refer to http://www.codeproject.com/Articles/26533/A-ServiceController-Class-that-Contains-the-Path-t
If you decide to use WMI (which I would prefer),
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Service");
ManagementObjectCollection collection = searcher.Get();
foreach (ManagementObject obj in collection)
{
string name = obj["Name"] as string;
string pathName = obj["PathName"] as string;
...
}
You can decide to wrap the properties you need in a class.
the interface has changed since #sidprasher answered, try:
var collection = searcher.Get().Cast<ManagementBaseObject>()
.Where(mbo => mbo.GetPropertyValue("StartMode")!=null)
.Select(mbo => Tuple.Create((string)mbo.GetPropertyValue("Name"), (string)mbo.GetPropertyValue("PathName")));
Is there a way I can get a list of all open applications and a list of all open files? For the files I only need the files that I opened (documents etc) not OS's open system files. The same for the applications (only browsers, document processors etc).
I already tried various functions from the Windows API like EnumWindows but I couldn't get what I wanted.
An example of what my ultimate goal would be, is to have lists like this:
Applications
Microsoft Word,
Notepad,
Mozilla Firefox
Files
foo.txt,
foo.mp3,
foo.doc
What I need is just the names, I don't need handles etc (even though I'm sure I'll have to use them to get what I want)
You can get a list of running processes with their information
public static string ListAllProcesses()
{
StringBuilder sb = new StringBuilder();
// list out all processes and write them into a stringbuilder
ManagementClass MgmtClass = new ManagementClass("Win32_Process");
foreach (ManagementObject mo in MgmtClass.GetInstances())
{
sb.Append("Name:\t" + mo["Name"] + Environment.NewLine);
sb.Append("ID:\t" + mo["ProcessId"] + Environment.NewLine);
sb.Append(Environment.NewLine);
}
return sb.ToString();
}
The only method (That I know) to see if the process is opened by user or system is to check it's owner. If it's system, then it's not run by user:
//You will need to reference System.Management.Dll and use System.Management namespace
public string GetProcessOwner(string processName)
{
string query = "Select * from Win32_Process Where Name = \"" + processName + "\"";
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
string owner = argList[1] + "\\" + argList[0];
return owner;
}
}
return "NO OWNER";
}
For the list of opened files, It is possible to do using Managed Code which is somehow hard. Here is an example on codeproject demonstrating the same matter
You can have a list of running processes with Process.GetProcesses(): http://msdn.microsoft.com/en-us/library/1f3ys1f9.aspx
But you can have the file they have open if they exposes some automation interface you know.