Reliable Mac inspectors for manufacturer, model, serial

I need to create some really bullet-proof, cross-platform relevance to collect some basic hardware information: manufacturer, model, and serial number.

I am 95% of the way there, but running into issues with two small minorities of Macs. Specifically, these seem to be 1. older macOS versions that are running the latest BigFix 9.5 client, and 2. a small subset of current macOS versions running the latest BigFix 10 client.

Here is just the Mac-specific part of the relevance I’m trying to use:

if exists smbios then ((unique values whose(it != "") of ((it as string as trimmed string) of values "vendor" of structures "bios_information" of smbios))) else "Apple Inc."

For subset (1) (older macOS, 9.5 client), this yields an “undefined” error:

The operator "smbios" is not defined.

Testing for the existence of smbios doesn’t appear to help. I have tried using a | to trap the error, but that also doesn’t appear to help. Does anyone have ideas on how to get around this error message?

For subset (2) (current macOS, latest 10 client), this yields an “error” error:

dmi inspector error creating dmi.info ([[CreateDmiInfoFromIOService: Unable to get the SMBIOS service.][CreateDmiInfoDevMem cannot open /dev/mem (2)][CreateDmiInfoMMap cannot open /dev/mem (2)]])

Again, I have attempted to use | to catch this error with no success. I am wondering if this might indicate a system where the BigFix Client doesn’t have the Full Disk Access permission or some similar permissions issue?

I also have a small subset of Windows systems that are throwing an error. Here is the Windows snippet of relevance I’m using:

string value of select "Manufacturer from Win32_ComputerSystem" of wmi

Around 1% of my Windows systems throw this “error” error:

The expression could not be evaluated: Windows Error 0x8007000e: Not enough memory resources are available to complete this operation.

My guess is that this is a transient error that may go away once the systems have restarted. But it would still be really handy to be able to reliably return a string like “N/A” instead of the error message for my use case.

For the interested, here are the full, cross-platform relevance strings I’m using for my analysis properties:

Serial Number - Universal

if windows of operating system then (string values of selects "IdentifyingNumber from Win32_ComputerSystemProduct" of wmi) else if mac of operating system then (string "IOPlatformSerialNumber" of dictionary of service plane of iokit registry) else if ((it contains "linux" OR it contains "hp-ux" OR it contains "sunos" OR it contains "aix") of (name of operating system as lowercase)) then (unique values whose(it != "") of (it as string as trimmed string) of values "serial_number" of structures "system_information" of smbios) else "N/A"

Serial Number 2 - Universal (this is a simplification of the previous that is almost as reliable but yields the errors above)

if (exists hardware) then (serial of hardware) else if (exists smbios) then (values "serial_number" of structures "system_information" of smbios as string) else "N/A"

Manufacturer - Universal

if windows of operating system then (string value of select "Manufacturer from Win32_ComputerSystem" of wmi) else if mac of operating system then (if exists smbios then (unique values whose(it != "") of ((it as string as trimmed string) of values "vendor" of structures "bios_information" of smbios)) else "Apple Inc.") else if ((it contains "linux" OR it contains "hp-ux" OR it contains "sunos" OR it contains "aix") of (name of operating system as lowercase)) then (unique values whose(it != "") of (it as string as trimmed string) of values "vendor" of structures "bios_information" of smbios) else ("N/A")

Model - Universal

if windows of operating system then (string values of selects "Model from Win32_ComputerSystem" of wmi as trimmed string) else if mac of operating system then (machine name as string) else if ((it contains "linux" OR it contains "hp-ux" OR it contains "sunos" OR it contains "aix") of (name of operating system as lowercase)) then (unique values whose(it != "") of (it as string as trimmed string) of values "product_name" of structures "system_information" of smbios) else "N/A"

Unique Identifier - Universal (this is ultimately what I’m trying to combine all of the previous properties into)

if windows of operating system then (concatenation "-" of ((string value of select "Manufacturer from Win32_ComputerSystem" of wmi);(string values of selects "Model from Win32_ComputerSystem" of wmi as trimmed string);(string values of selects "IdentifyingNumber from Win32_ComputerSystemProduct" of wmi))) else if mac of operating system then (concatenation "-" of ((if exists smbios then (unique values whose(it != "") of ((it as string as trimmed string) of values "vendor" of structures "bios_information" of smbios)) else "Apple Inc.");(machine name as string);(string "IOPlatformSerialNumber" of dictionary of service plane of iokit registry))) else if ((it contains "linux" OR it contains "hp-ux" OR it contains "sunos" OR it contains "aix") of (name of operating system as lowercase)) then (concatenation "-" of ((unique values whose(it != "") of (it as string as trimmed string) of values "vendor" of structures "bios_information" of smbios);(unique values whose(it != "") of (it as string as trimmed string) of values "product_name" of structures "system_information" of smbios);(unique values whose(it != "") of (it as string as trimmed string) of values "serial_number" of structures "system_information" of smbios))) else ("N/A")

Any suggestions on making these as reliable as possible would be very welcome!

The use case is for a Service Now integration where we really needs these properties to be very reliably populated. We are trying to use the combination of these “immutable” properties of systems to uniquely id systems in Service Now, even across a system rebuild (which is why we’re not relying on the BigFix ID).

Thanks,

Jeremy.

That’s some really great work… I don’t have solutions on every part of it right now but I can help on a couple of points

if exists smbios then

This existence check would work if we were checking “does this object exist on the computer”, but it does not work for checking “does this inspector exist on this version of client”. The client version would have to know how to create an smbios object to check whether it succeeds, but you can’t try that on really old clients that don’t know smbios.

What you can check though is whether the smbios property exists, similar to how we check for Proxy Agents in some content

if exists property "smbios" and exists smbios then ... else .... 

Or.maybe

if exists property "smbios" then if exists smbios then ... else .... else ....

The dmi error may be a full-disk-access thing…generally we could trap an error with the pipe operator "|"

If exists property "smbios" and exists smbios then (<value lookup> | "Apple, Inc., without Full-Disk Access")
1 Like

I’m away from computer today but should be able to look at this more tomorrow. On Windows, I’d generally prefer using the dmi or smbios inspectors instead of wmi anyway - wmi basically spawns off a new process 5o perform wmi lookups, which could have any number of runtime errors, but dmi and smbios lookups are based on a cache the client builds when the service starts up, so it’s a lot less prone to errors.

Thanks, Jason! This was extremely helpful.

Using your suggestions, I reformulated the relevance:

Serial Number - Universal

if mac of operating system and exists property "iokit registry" then (string "IOPlatformSerialNumber" of dictionary of service plane of iokit registry) else if exists property "hardware" then (if exists hardware then (serial of hardware|"N/A") else "N/A") else if exists property "smbios" then (if exists smbios then (values "serial_number" of structures "system_information" of smbios as string|"N/A") else "N/A") else "N/A"

So far, that seems to work for all of the systems that have reported in with no errors.

Manufacturer - Universal

if mac of operating system then "Apple, Inc." else if exists property "smbios" then (if exists smbios then ((unique value whose(it != "") of (it as string as trimmed string) of values "vendor" of structures "bios_information" of smbios)) else "N/A") else "N/A"

I really hate the ugly Mac hack at the beginning, but barring the very rare Hackintosh I think the assumption that any system for which mac of operating system is true will be from Apple. Only one system, a Raspberry Pi, is showing up as “N/A”—everything else appears to be reporting accurately. (Though I have nothing nice to say about manufacturers who leave this set to “Default String” or “To be filled in by OEM” :angry:.)

Model - Universal

if mac of operating system then (if exists property "machine name" then (machine name as string) else "N/A-Mac") else if exists property "smbios" then (if exists smbios then (unique value whose(it != "") of (it as string as trimmed string) of values "product_name" of structures "system_information" of smbios) else "N/A") else "N/A"

This seems to work reliably, as well. Same issues with the Raspberry Pi and sloppy manufacturers, but I don’t think there’s anything BigFix can do about those.

I did note that trying to combine the property and direct statements like if exists property "smbios" and exists smbios still seems to error out on some systems. That’s why I reframed some of those as if exists property "smbios" then (if exists smbios then (<do stuff>)), which seems to work as expected.

I want to do some more testing, but once I get these into a stable format I plan to post the final analysis to BigFix.me.

I would still welcome suggestions on further refinement!

1 Like

This is the relevance we used for several years to get manufacturer and model. Maybe another approach that could be of use for Mac and can still add that extra level of smbios checks that you have (assuming the approach is still current…I’m not a Mac user) :wink:

Manufacturer
(if (windows of it or unix of it) then (value "manufacturer" of structure "system_information" of smbios as string as trimmed string) else (if(mac of it) then (cstring "manufacturer" of dictionary of devicetree plane of iokit registry) else (nothing))) of operating system

Model
(if (windows of it or unix of it) then (value "product_name" of structure "system_information" of smbios as string as trimmed string) else (if(mac of it) then (cstring "model" of dictionary of devicetree plane of iokit registry) else (nothing))) of operating system

1 Like

We’re using these in a Windows/Mac client dashboard. Given this discussion, I might rework the Windows parts away from WMI. I recall deliberately putting Windows first, as more computers will hit a positive result first.

Manufacturer

if (windows of operating system) then (if (exists wmi) then (string values of selects "Manufacturer from Win32_ComputerSystem" of wmi) else ("N/A")) else if (mac of operating system) then ("Apple") else "n/a"

Model

if (windows of operating system) then (if (exists wmi) then (string values of selects "Model from Win32_ComputerSystem" of wmi) else ("N/A")) else if (mac of operating system) then (machine name) else "n/a"

Serial Number

if (windows of operating system) then (if (exists wmi) then ((string values of selects "IdentifyingNumber from Win32_ComputerSystemProduct" of wmi) as string) else "None") else if (mac of operating system) then (if (exists iokit registry) then (string "IOPlatformSerialNumber" of dictionary of service plane of iokit registry) else "None") else "-NA-" as string
1 Like

My official position is that any Hackintosh can GTFO. :wink:

I should have thought to reach out to you on this question, Andrew! I’m sure that most UCs have the need for strong cross-platform support.

1 Like