How to get a unique computer identifier in Java (like disk ID or motherboard ID)?

111,322

Solution 1

It is common to use the MAC address is associated with the network card.

The address is available in Java 6 through through the following API:

Java 6 Docs for Hardware Address

I haven't used it in Java, but for other network identification applications it has been helpful.

Solution 2

The problem with MAC address is that there can be many network adapters connected to the computer. Most of the newest ones have two by default (wi-fi + cable). In such situation one would have to know which adapter's MAC address should be used. I tested MAC solution on my system, but I have 4 adapters (cable, WiFi, TAP adapter for Virtual Box and one for Bluetooth) and I was not able to decide which MAC I should take... If one would decide to use adapter which is currently in use (has addresses assigned) then new problem appears since someone can take his/her laptop and switch from cable adapter to wi-fi. With such condition MAC stored when laptop was connected through cable will now be invalid.

For example those are adapters I found in my system:

lo MS TCP Loopback interface
eth0 Intel(R) Centrino(R) Advanced-N 6205
eth1 Intel(R) 82579LM Gigabit Network Connection
eth2 VirtualBox Host-Only Ethernet Adapter
eth3 Sterownik serwera dostepu do sieci LAN Bluetooth

Code I've used to list them:

Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
while (nis.hasMoreElements()) {
    NetworkInterface ni = nis.nextElement();
    System.out.println(ni.getName() + " " + ni.getDisplayName());
}

From the options listen on this page, the most acceptable for me, and the one I've used in my solution is the one by @Ozhan Duz, the other one, similar to @finnw answer where he used JACOB, and worth mentioning is com4j - sample which makes use of WMI is available here:

ISWbemLocator wbemLocator = ClassFactory.createSWbemLocator();
ISWbemServices wbemServices = wbemLocator.connectServer("localhost","Root\\CIMv2","","","","",0,null);
ISWbemObjectSet result = wbemServices.execQuery("Select * from Win32_SystemEnclosure","WQL",16,null);
for(Com4jObject obj : result) {
    ISWbemObject wo = obj.queryInterface(ISWbemObject.class);
    System.out.println(wo.getObjectText_(0));
}

This will print some computer information together with computer Serial Number. Please note that all classes required by this example has to be generated by maven-com4j-plugin. Example configuration for maven-com4j-plugin:

<plugin>
    <groupId>org.jvnet.com4j</groupId>
    <artifactId>maven-com4j-plugin</artifactId>
    <version>1.0</version>
    <configuration>
        <libId>565783C6-CB41-11D1-8B02-00600806D9B6</libId>
        <package>win.wmi</package>
        <outputDirectory>${project.build.directory}/generated-sources/com4j</outputDirectory>
    </configuration>
    <executions>
        <execution>
            <id>generate-wmi-bridge</id>
            <goals>
                <goal>gen</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Above's configuration will tell plugin to generate classes in target/generated-sources/com4j directory in the project folder.

For those who would like to see ready-to-use solution, I'm including links to the three classes I wrote to get machine SN on Windows, Linux and Mac OS:

Solution 3

The OSHI project provides platform-independent hardware utilities.

Maven dependency:

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>LATEST</version>
</dependency>

For instance, you could use something like the following code to identify a machine uniquely:

import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.ComputerSystem;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;

class ComputerIdentifier
{
    static String generateLicenseKey()
    {
        SystemInfo systemInfo = new SystemInfo();
        OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
        HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware();
        CentralProcessor centralProcessor = hardwareAbstractionLayer.getProcessor();
        ComputerSystem computerSystem = hardwareAbstractionLayer.getComputerSystem();

        String vendor = operatingSystem.getManufacturer();
        String processorSerialNumber = computerSystem.getSerialNumber();
        String processorIdentifier = centralProcessor.getIdentifier();
        int processors = centralProcessor.getLogicalProcessorCount();

        String delimiter = "#";

        return vendor +
                delimiter +
                processorSerialNumber +
                delimiter +
                processorIdentifier +
                delimiter +
                processors;
    }

    public static void main(String[] arguments)
    {
        String identifier = generateLicenseKey();
        System.out.println(identifier);
    }
}

Output for my machine:

Microsoft#57YRD12#Intel64 Family 6 Model 60 Stepping 3#8

Your output will be different since at least the processor serial number will differ.

Solution 4

What do you want to do with this unique ID? Maybe you can do what you want without this ID.

The MAC address maybe is one option but this is not an trusted unique ID because the user can change the MAC address of a computer.

To get the motherboard or processor ID check on this link.

Solution 5

On Windows only, you can get the motherboard ID using WMI, through a COM bridge such as JACOB.

Example:

import java.util.Enumeration;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.EnumVariant;
import com.jacob.com.Variant;

public class Test {
    public static void main(String[] args) {
        ComThread.InitMTA();
        try {
            ActiveXComponent wmi = new ActiveXComponent("winmgmts:\\\\.");
            Variant instances = wmi.invoke("InstancesOf", "Win32_BaseBoard");
            Enumeration<Variant> en = new EnumVariant(instances.getDispatch());
            while (en.hasMoreElements())
            {
                ActiveXComponent bb = new ActiveXComponent(en.nextElement().getDispatch());
                System.out.println(bb.getPropertyAsString("SerialNumber"));
                break;
            }
        } finally {
            ComThread.Release();
        }
    }
}

And if you choose to use the MAC address to identify the machine, you can use WMI to determine whether an interface is connected via USB (if you want to exclude USB adapters.)

It's also possible to get a hard drive ID via WMI but this is unreliable.

Share:
111,322
Gohu
Author by

Gohu

Updated on July 05, 2022

Comments

  • Gohu
    Gohu almost 2 years

    I'd like to get an id unique to a computer with Java, on Windows, MacOS and, if possible, Linux. It could be a disk UUID, motherboard S/N...

    Runtime.getRuntime().exec can be used (it is not an applet).

    Ideas?

  • Gohu
    Gohu over 14 years
    I've think about it, but when the network card isn't connected, i can't get any MAC address
  • Steve Kuo
    Steve Kuo over 14 years
    It's also possible for the user to switch network cards. On some laptops, when running off battery, the (wired) Ethernet card is disabled to save battery power, and is thus not visible to the operating system.
  • BalusC
    BalusC over 14 years
    Links which you placed behind cpuid/moboserial describes Windows-specific ways. This isn't crossplatform.
  • Michel Gokan Khan
    Michel Gokan Khan over 14 years
    in linux you can get hdd serial number using this command : hdparm -i /dev/sda1 | awk '/SerialNo=/{print $NF}' ( just recognize OS and try different methods ) you can find MB serial number using lshw command
  • Alex Fedulov
    Alex Fedulov about 12 years
    And do not forget that one does not even need to change the network card in order to spoof MAC: aboutlinux.info/2005/09/how-to-change-mac-address-of-your.ht‌​ml
  • Alex Fedulov
    Alex Fedulov about 12 years
    And do not expect antiviruses to allow strange vbs scripts appearing on your hard drive. Most of them will immediately block the file, before you will have a chance to execute it.
  • thouliha
    thouliha over 8 years
    This isn't really doable for me, since it requires root on linux.
  • David
    David about 8 years
    I tried using MAC address on virtual machines, and found it just wasn't stable enough. Unless you can guarantee stable mac addresses across VM moves and reboots, using the MAC address as a machine identifier will cause you problems. See the answer below from Bartosz Fiyrn for a better approach
  • Horcrux7
    Horcrux7 over 7 years
    On Windows Nano Server 2016 the format is "SerialNumber = xxx". The sample code will return ever "=" as serial number. On other Windows installation it works for me.
  • user489041
    user489041 about 7 years
    Just to note, some of these operations require root access depending on your OS. Might be a limiting factor
  • Rafat Rifaie
    Rafat Rifaie over 2 years
    @user489041 What operations and on what OSs?