I am making my own hardware monitor like CPU-Z, I am trying to acquire my dedicated graphics card information, but it only returns my processors integrated graphics.
public string GetPart(string part)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM " + "Win32_Videocontroller");
foreach (ManagementObject mobj in searcher.Get())
{
partval = mobj["Name"] as string;
}
return partval;
This returns Intel(R) UHD Graphics 630
For other applicable parts like hard drive, fans, or even the rare case of multiple processor sockets, how would I go about indexing these?
I have had some problems with this laptop revolving around my gpu, it could be possible that it 'isn't detected' as Task Manager does not show GPU1 ever being used, and the performance tab shows absurdly low usage even when running a game like WoW on max settings, especially on a laptop.
Background: I created an app for our unit's Help Desk that grabs computer information for an asset database. Recently someone doing inventory said that a user had a USB external hard drive connected and that my app was including it in the total hard drive space.
How do I get the total hard drive size using Win32 ManagementObjects while ignoring external/USB devices?
I'm willing to use another Win32ManagementObjects items such as Win32_PhysicalMedia, Win32_LogicalDisk, or Win32_DiskPartition, but:
I'm only interested in the total internal storage (don't actually care about partitions or logical drives)
I'm more interested in figuring out what the bug is in the code below
Here's what I have:
long totalSize = 0;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32ManagementObjects.Win32_DiskDrive");
// there may be multiple hard drives, so loop through them all
foreach (ManagementObject mo in searcher.Get())
{
/*
* I assume this is where the problem is. I check that the drive type
* includes "FIXED HARD DISK" (see reference link below)
*/
mediaType = mo.Properties["MediaType"].Value.ToString().ToUpper();
if (mediaType.IndexOf("FIXED HARD DISK") >= 0)
{
totalSize += Convert.ToInt64(mo.Properties["Size"].Value.ToString());
}
}
Could this particular USB drive just be reporting bad information to the operating system? Is that possible? It's basically impossible for me to debug since the user's computer is off-site.
Reference: https://msdn.microsoft.com/en-us/library/aa394132(v=vs.85).aspx
I can get the totalsize of my fixed disks excluding ones connected through USB with this code
long totalSize = 0;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
// there may be multiple hard drives, so loop through them all
foreach (ManagementObject mo in searcher.Get())
{
if (mo.Properties["InterfaceType"].Value.ToString() != "USB")
{
totalSize += Convert.ToInt64(mo.Properties["Size"].Value.ToString());
}
}
Trying your code I receieved a NullReferenceException when reading the value of the property MediaType.ToString(), so, I assume that this property is not always set. Probably you could try to work around the NullReference adding string.IsNullOrEmpty before checking for "FIXED HARD DISK", but I have no certainity that this property is never null on a fixed disk.
By the way, using Win32ManagementObjects.Win32_DiskDrive gives me a ManagementException InvalidQuery I have to remove the Win32ManagementObjects string and leave only Win32_DiskDrive
You can use the classic Win32 function GetDriveType() and check for DRIVE_REMOVABLE and DRIVE_FIXED.
I have a bunch of iSCSI drives mounted as NFTS folders (to avoid exhausting all the drive letters) acting as a mini SAN, and I would like to get the information about their free space. The basic reason is to get warnings when space gets below a certain threshold, as a part of a scheduled task which does a bunch of other checks.
Is there a way to do it, preferably using C# (through WMI, P/Invoke, or whatever)? Of course, any scripting solution would also be great, as I can probably invoke it anyway (PowerShell)? I tried the optimistic route first, using DriveInfo initialized with using such a path, but it simply returns information about the root volume instead of the mount. I've also tried enumerating stuff like Win32_DiskPartition, Win32_LogicalDisk and Win32_MappedLogicalDisk but didn't get those drives at all.
As #FrédéricHamidi explained, Win32_Volume class in the WMI Storage Volume Provider shows correct space information about mounted volumes.
Usage example (C#) would be something like:
// iSCSI drive mounted in a NTFS folder
var ntfsPath = #"x:\iscsi\volume";
// it's good to know that backspaces must be escaped in WMI queries
var cmd = string.Format(
"SELECT * FROM Win32_Volume WHERE Name LIKE '{0}%'",
ntfsPath.Replace(#"\", #"\\"));
using (var searcher = new ManagementObjectSearcher(cmd))
{
foreach (ManagementObject queryObj in searcher.Get())
{
var name = (string)queryObj["Name"];
var freeSpaceInBytes = (ulong)queryObj["FreeSpace"];
}
}
I am trying to identify a screen in a multi-monitor setup to save some data linked to that screen. How can I reliable identify a screen, also after a reboot?
I am aware of the Screen class in .Net but Screen.DeviceName seems not be consistently pointing to one screen (for example after installing a new graphics driver).
Try WMI instead of WinForms.
The following post shows how to get monitors and their details (s. DisplayDetails
class e.g.): Monitor ID and Serial Number
Edit:
My suggestion:
using System.Management;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DesktopMonitor");
foreach (ManagementObject obj in searcher.Get())
Console.WriteLine("PNP Device ID: {0}", obj ["PNPDeviceID"]);
I solved this by getting the DeviceID with the EnumDisplayDevices API. Seems to be unique for each screen and does not change after a driver update for example.
WMI is out of the question for me as I tried it before and it only returns one monitor with my multi-monitor setup.
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();