Jump to content

How to query BIOS S/N in C#?

Windows7ge
Go to solution Solved by Mojo-Jojo,

Upon having another look at the WMI spec, it seems like Win32_SystemBIOS is not the correct class to use.

Win32_SystemBIOS simply contains the Win32_BIOS and Win32_ComputerSystem classes.

 

You already tried to use Win32_BIOS later, which should be what the WMIC command selects as well.

 

I think this is rather an issue of using ManagementObject correctly.

I can't try out code for you sadly, since I don't have Visual Studio installed and don't often program in C#.

But looking at the documentation, a ManagementObject has a Properties->Value property, which might yield the desired results.

 

So what I would try is a simplified form of what you tried, without the object searcher:

ManagementObject BiosObject = new ManagementObject("Win32_BIOS");
string MySN = BiosObject.Properties["SerialNumber"].Value.ToString();

Let me start with, I'm a novice at programming. Be gentile with throwing around fancy vocabulary because I don't understand 99% of it. Or at least provide a code snippet explaining what you're saying. Sorry and thank you.

 

So I wrote a rudimentary Windows Form in C# which quires system hardware information and allows for the selection of tests to perform to ensure hardware functionality. It's still a work in progress so it's a bit of a mess at the moment:

using OnBarcode.Barcode;
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace WorkbenchTestingTool_NET4._8._1
{
    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
        }
        private void Main_Load(object sender, EventArgs e)
        {
            Int64 memory = 0;

            ManagementObject myManagementObject = new ManagementObject("Win32_OperatingSystem=@");
            string MySN = (string)myManagementObject["SerialNumber"];

            Linear barcode = new Linear();
            barcode.Type = BarcodeType.CODE128;
            barcode.Data = MySN;
            picBarcode.Image = barcode.drawBarcode();

            ManagementObjectSearcher mySerialObject = new ManagementObjectSearcher("select SerialNumber from Win32_BIOS");
            foreach (ManagementObject obj in mySerialObject.Get())
            {

                listHardware.Items.Add(obj);
            }

            ManagementObjectSearcher myProcessorObject = new ManagementObjectSearcher("select Name from Win32_Processor");
            foreach (ManagementObject obj in myProcessorObject.Get()) { listHardware.Items.Add("CPU: " + obj["Name"]); }

            ManagementObjectSearcher myMemoryObject = new ManagementObjectSearcher("select Capacity from Win32_PhysicalMemory");
            foreach (ManagementObject obj in myMemoryObject.Get()) { memory += Convert.ToInt64(obj["Capacity"]); }
            listHardware.Items.Add("RAM: " + (memory / 1048576) + " MiB");

            DriveInfo[] allDrives = DriveInfo.GetDrives();
            foreach (DriveInfo d in allDrives) { if (d.DriveType == DriveType.Fixed) { listHardware.Items.Add("STG: " + (Convert.ToInt64(d.TotalSize) / 1073741824) + " GiB"); } }
          
            ManagementObjectSearcher myVideoObject = new ManagementObjectSearcher("select Name from Win32_VideoController");
            foreach (ManagementObject obj in myVideoObject.Get()) { listHardware.Items.Add("GPU: " + obj["Name"]); }
          
        }
        private void btnRunTest_Click(object sender, EventArgs e)
        {
            if (checkCamera.Checked == true) { execute("camera.bat"); }
            if (checkArrowKeys.Checked == true) { execute("arrowkeys.bat"); }
            if (checkInternetAudio.Checked == true) { execute("internetaudio.bat"); }
            if (checkKeyboardLCD.Checked == true) { execute("keyboardscreen.bat"); }
        }
        private void btnCheckActivation_Click(object sender, EventArgs e)
        {
            execute("activationstatus.bat");
        }
        private void btnRunTweaks_Click(object sender, EventArgs e)
        {
            if (checkScreenBright100.Checked == true) { execute("brightness100.bat"); }
            if (checkConnectWiFi.Checked == true) { execute("wifi.bat"); }
        }
        private void execute(string input)
        {
            Process p = new Process();
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.FileName = "./bat/" + input;
            p.Start();

            if (input == "serialnumber.bat") //||
                //input == "cpuname.bat" ||
                //input == "memory.bat" ||
                //input == "storage.bat" ||
                //input == "gpuname.bat")
            {
               // string output = p.StandardOutput.ReadToEnd();

                if (input == "serialnumber.bat")
                {
                   
                }

               // else if (input == "cpuname.bat") { listHardware.Items.Add("CPU: " + output.Remove(0, 5)); }
               // else if (input == "memory.bat") { listHardware.Items.Add("RAM: " + output.Remove(0, 27)); }
               // else if (input == "storage.bat") { listHardware.Items.Add("STG: " + (Convert.ToInt64(output) / 1073741824) + " GB"); }
               // else if (input == "gpuname.bat") { listHardware.Items.Add("GPU: " + output); }
            }

            p.WaitForExit();
        } 
    }
}

 

I originally got everything working by starting a process which launched a series of batch files but since I've validated the overall functionality I want to make the code better by removing that dependency as much as I can.

 

At this time I've removed four .bat files from the config for hardware queries at the top by using ManagementObjectSearcher. Based on my implementation so far I really like it but I've hit a brick wall and none of my Google-Fu is helping.

 

To get the BIOS S/N I currently use the CMD command wmic bios get serialnumber | findstr /v "SerialNumber" which in my VM testing environment outputs a string like this: VMware-42 25 79 21 20 6d 82 e6-52 cd 28 b2 e9 c5 31 2e

 

This then gets passed to a barcode generator which produces a .png barcode on the Windows Form that I can scan on screen. This is the desire.

 

Problem: I can't find anything on Google explaining what sounds on paper like a really simple task. I have tried the following methods to query the BIOS S/N:

ManagementObjectSearcher mySerialObject = new ManagementObjectSearcher("select SerialNumber from Win32_BIOS");
foreach (ManagementObject obj in mySerialObject.Get())
            {
            Linear barcode = new Linear();
            barcode.Type = BarcodeType.CODE128;
            barcode.Data = obj;
            picBarcode.Image = barcode.drawBarcode();
            }

ManagementObjectSearcher mySerialObject = new ManagementObjectSearcher("select SerialNumber from Win32_SystemBIOS");
<foreach identical>

ManagementObjectSearcher mySerialObject = new ManagementObjectSearcher("select SerialNumber from Win32_BaseBoard");
<foreach identical>

ManagementObject myManagementObject = new ManagementObject("Win32_OperatingSystem=@");
            string MySN = (string)myManagementObject["SerialNumber"];

The first three generate no output. Just empty strings. The fourth generates the wrong information.

 

So I'm left wondering. Where does wmic bios get serialnumber get it's information from? Either I'm not formatting/converting the output correctly or CMD's wmic goes somewhere I'm not looking.

 

I'm going to keep looking but I'm running out of ideas and websites to click on. Not sure where else to look or what to type into Google.

Link to comment
Share on other sites

Link to post
Share on other sites

2 minutes ago, Mojo-Jojo said:

Why not directly execute the wmic command and parse its output?

This is something I was researching as well, to see if there was a way to execute it and format the output string without using a batch file but I couldn't really find a resource to explain how to do that. Unless wmic is something I can call directly. Which I would have to research too.

Link to comment
Share on other sites

Link to post
Share on other sites

Are you following the directions from Microsoft themselves on properly connecting to WMI using the right namespace and methods?

 

Connecting to WMI Remotely with C# - Win32 apps | Microsoft Learn

 

The instructions are for a remote machine but also work for the local machine as well

PLEASE QUOTE ME IF YOU ARE REPLYING TO ME

Desktop Build: Ryzen 7 2700X @ 4.0GHz, AsRock Fatal1ty X370 Professional Gaming, 48GB Corsair DDR4 @ 3000MHz, RX5700 XT 8GB Sapphire Nitro+, Benq XL2730 1440p 144Hz FS

Retro Build: Intel Pentium III @ 500 MHz, Dell Optiplex G1 Full AT Tower, 768MB SDRAM @ 133MHz, Integrated Graphics, Generic 1024x768 60Hz Monitor


 

Link to comment
Share on other sites

Link to post
Share on other sites

4 minutes ago, rcmaehl said:

Are you following the directions from Microsoft themselves on properly connecting to WMI using the right namespace and methods?

 

Connecting to WMI Remotely with C# - Win32 apps | Microsoft Learn

I believe the namespace is correct because my queries for CPU, GPU, & RAM also rely on using System.Management. Their queries are successful.

The method should be the same for all of them. I'm using Microsoft Visual Studio's. It's pretty good at yelling at me when a call I make to the system doesn't have a corresponding recipient.

 

Say I ask for the SerialNumber1. If the field doesn't exist or worse Win32_BIOSs (deliberate mistype) doesn't exist it let's me know fast. Everything crashes and it points in the general area that it stopped executing. Helpful.

 

So I'm led to believe it's finding the WMI menu, it's finding the name of the entry I'm requesting but somewhere in-between the value and bringing it to the UI it's not connecting. Can't figure out why but the harder I think about it the more I feel like its a simple issue and I'm over-thinking it. 😆

Link to comment
Share on other sites

Link to post
Share on other sites

Upon having another look at the WMI spec, it seems like Win32_SystemBIOS is not the correct class to use.

Win32_SystemBIOS simply contains the Win32_BIOS and Win32_ComputerSystem classes.

 

You already tried to use Win32_BIOS later, which should be what the WMIC command selects as well.

 

I think this is rather an issue of using ManagementObject correctly.

I can't try out code for you sadly, since I don't have Visual Studio installed and don't often program in C#.

But looking at the documentation, a ManagementObject has a Properties->Value property, which might yield the desired results.

 

So what I would try is a simplified form of what you tried, without the object searcher:

ManagementObject BiosObject = new ManagementObject("Win32_BIOS");
string MySN = BiosObject.Properties["SerialNumber"].Value.ToString();
Link to comment
Share on other sites

Link to post
Share on other sites

3 hours ago, Mojo-Jojo said:

So what I would try is a simplified form of what you tried, without the object searcher:

I'll give it a shot when I have time after work today.

 

I actually don't know how important ManagementObjectSearcher is if my foreach loop queries multiple items.

 

For the S/N I only need one single string/output.

 

For the other queries (which are working as intended) I wonder if they actually need it as they might loop more than once (designing with future applications in mind). I might just trial & error test that. I like removing unneeded code. Make it simpler to look at.

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×