cheat sheet
system_profiler
Deep-dive on system_profiler(8) — macOS's built-in inventory tool. Covers data types, text/XML/JSON output, piping into jq and plutil, common SP* probes (hardware, displays, memory, storage, USB, network, software), detail levels, and fleet inventory recipes.
system_profiler — macOS Hardware & Software Inventory
What it is
system_profiler(8) is the command-line equivalent of the macOS GUI app System Information (formerly "About this Mac → System Report"). It dumps a structured inventory of everything the OS knows about the machine — CPU, RAM, displays, internal and external storage, USB topology, network interfaces, Wi-Fi, audio, printers, installed software, kernel extensions, applications, even environment variables — partitioned into ~80 named "data types" you query individually. It ships with macOS at /usr/sbin/system_profiler and runs as a regular user (some data types require root). Reach for it when you need a complete machine-readable snapshot for fleet inventory, asset management imports, support tickets, or to discover a specific model identifier / serial / firmware version from a script. On Windows, the closest analogue is systeminfo + Get-ComputerInfo; on Linux, dmidecode + lshw.
Install
system_profiler ships with every macOS install at /usr/sbin/system_profiler — nothing to install. The GUI counterpart, System Information, lives at /System/Library/CoreServices/Applications/System Information.app and shares the same backend.
which system_profiler
system_profiler -h 2>&1 | head -10
Output:
/usr/sbin/system_profiler
Usage: system_profiler [-listDataTypes]
system_profiler [-xml | -json] [-detailLevel level] [datatype1 ... datatypeN]
system_profiler [-xml | -json] -timeout n -detailLevel level
system_profiler -listDataTypes
system_profiler -usage
Syntax
The bare form (no arguments) dumps every data type at the default detail level — useful, but slow (~30–60 seconds) and verbose (10–50 MB of text). For day-to-day work, query a single data type (SPHardwareDataType, SPDisplaysDataType), choose a detail level, and pick a machine-readable output format.
system_profiler [DATATYPE...] # plain text dump
system_profiler -xml [DATATYPE...] # plist XML
system_profiler -json [DATATYPE...] # JSON (macOS 12+)
system_profiler -listDataTypes # available data types
system_profiler -detailLevel mini|basic|full DATATYPE # control verbosity
system_profiler -timeout SECONDS # cap collection time
Output: (none — exits 0 on success)
Essential options
| Option | Meaning |
|---|---|
-listDataTypes | List every data type the system supports (~80 entries) |
-xml | Output a binary plist as XML (suitable for plutil) |
-json | Output JSON — macOS 12+ only (suitable for jq) |
-detailLevel mini | Smallest output; coarse counts, no nested arrays |
-detailLevel basic | Default for most data types |
-detailLevel full | Most verbose — adds binary blobs, firmware paths, S/N |
-timeout SECONDS | Force-finish if a probe takes too long (default ~10s per type) |
-usage | Per-data-type detail-level help: system_profiler SPHardwareDataType -usage |
-nospawn | Run probes in-process (no per-type subprocesses) |
Listing available data types
-listDataTypes enumerates everything queryable. The set is essentially fixed across modern macOS but grows slightly with new Apple Silicon generations (e.g. SPSecureElementDataType appeared with Touch ID Macs). Each data type follows the SP*DataType naming convention.
system_profiler -listDataTypes
Output:
Available Datatypes:
SPParallelATADataType
SPUniversalAccessDataType
SPSecureElementDataType
SPApplicationsDataType
SPAudioDataType
SPBluetoothDataType
SPCameraDataType
SPCardReaderDataType
SPiBridgeDataType
SPDeveloperToolsDataType
SPDiagnosticsDataType
SPDisabledSoftwareDataType
SPDiscBurningDataType
SPEthernetDataType
SPExtensionsDataType
SPFibreChannelDataType
SPFireWireDataType
SPFirewallDataType
SPFontsDataType
SPFrameworksDataType
SPDisplaysDataType
SPHardwareDataType
SPInstallHistoryDataType
SPInternationalDataType
SPLegacySoftwareDataType
SPNetworkLocationDataType
SPLogsDataType
SPManagedClientDataType
SPMemoryDataType
SPNVMeDataType
SPNetworkDataType
SPPCIDataType
SPParallelSCSIDataType
SPPowerDataType
SPPrefPaneDataType
SPPrintersSoftwareDataType
SPPrintersDataType
SPConfigurationProfileDataType
SPRawCameraDataType
SPSASDataType
SPSerialATADataType
SPSPIDataType
SPSmartCardsDataType
SPSoftwareDataType
SPStartupItemDataType
SPStorageDataType
SPSyncServicesDataType
SPThunderboltDataType
SPUSBDataType
SPNetworkVolumeDataType
SPWWANDataType
SPAirPortDataType
The most commonly used 10 (in my experience):
| Data type | What it reports |
|---|---|
SPHardwareDataType | Model, chip, cores, RAM total, serial number, hardware UUID |
SPSoftwareDataType | macOS version, build, kernel, boot mode, user/computer name |
SPDisplaysDataType | Graphics controllers + every connected display (res, EDID) |
SPMemoryDataType | Total RAM, ECC state, manufacturer; per-DIMM detail on Intel Macs |
SPStorageDataType | Each mounted volume: type, BSD name, capacity, free space, role |
SPNetworkDataType | Every network service (Wi-Fi, Ethernet, VPN) with IP/route/DNS |
SPUSBDataType | Full USB topology (hubs + downstream devices) |
SPBluetoothDataType | BT controller + paired/connected devices |
SPApplicationsDataType | Every installed .app with path, version, signature |
SPPowerDataType | Battery state, AC adapter wattage, sleep settings |
Plain text output
The default format is human-readable indented text — the same content you'd see in System Information.app. Suitable for support tickets, but a chore to parse.
system_profiler SPHardwareDataType
Output:
Hardware:
Hardware Overview:
Model Name: MacBook Pro
Model Identifier: Mac14,9
Model Number: MNW93LL/A
Chip: Apple M2 Pro
Total Number of Cores: 10 (6 performance and 4 efficiency)
Memory: 16 GB
System Firmware Version: 10151.121.1
OS Loader Version: 10151.121.1
Serial Number (system): XXXXXXXXXXX
Hardware UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Provisioning UDID: XXXXXXXX-XXXXXXXXXXXXXXXX
Activation Lock Status: Enabled
system_profiler SPSoftwareDataType
Output:
Software:
System Software Overview:
System Version: macOS 15.5 (24F74)
Kernel Version: Darwin 24.5.0
Boot Volume: Macintosh HD
Boot Mode: Normal
Computer Name: My MacBook Pro
User Name: Alice Dev (alicedev)
Secure Virtual Memory: Enabled
System Integrity Protection: Enabled
Time since boot: 5 days, 14 hours, 22 minutes
JSON output and jq piping
-json was added in macOS Monterey (12) and is the cleanest way to extract specific values in scripts. Pipe into jq for selection and transformation.
system_profiler -json SPHardwareDataType
Output:
{
"SPHardwareDataType" : [
{
"_name" : "hardware_overview",
"activation_lock_status" : "activation_lock_enabled",
"boot_rom_version" : "10151.121.1",
"chip_type" : "Apple M2 Pro",
"machine_model" : "Mac14,9",
"machine_name" : "MacBook Pro",
"model_number" : "MNW93LL/A",
"number_processors" : "proc 10:6:4",
"os_loader_version" : "10151.121.1",
"physical_memory" : "16 GB",
"platform_UUID" : "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"provisioning_UDID" : "XXXXXXXX-XXXXXXXXXXXXXXXX",
"serial_number" : "XXXXXXXXXXX"
}
]
}
# Specific value — chip name
system_profiler -json SPHardwareDataType | jq -r '.SPHardwareDataType[0].chip_type'
Output:
Apple M2 Pro
# Multiple values into a CSV row
system_profiler -json SPHardwareDataType SPSoftwareDataType | \
jq -r '[
.SPHardwareDataType[0].machine_name,
.SPHardwareDataType[0].chip_type,
.SPHardwareDataType[0].physical_memory,
.SPHardwareDataType[0].serial_number,
.SPSoftwareDataType[0].os_version
] | @csv'
Output:
"MacBook Pro","Apple M2 Pro","16 GB","XXXXXXXXXXX","macOS 15.5 (24F74)"
# Total storage capacity in GB
system_profiler -json SPStorageDataType | \
jq '[.SPStorageDataType[] | .size_in_bytes] | add / 1e9 | round'
Output:
494
XML output and plutil
Pre-Monterey systems and some data types still emit cleaner data via XML. The plutil tool converts between binary plist, XML plist, and JSON — perfect for older macOS targets or when you want to embed the dump inside an XML-aware system.
system_profiler -xml SPHardwareDataType | head -25
Output:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>_SPCommandLineArguments</key>
<array>
<string>/usr/sbin/system_profiler</string>
<string>-nospawn</string>
<string>-xml</string>
<string>-detailLevel</string>
<string>full</string>
<string>SPHardwareDataType</string>
</array>
<key>_dataType</key>
<string>SPHardwareDataType</string>
<key>_items</key>
<array>
<dict>
<key>_name</key>
<string>hardware_overview</string>
</dict>
</array>
</dict>
</array>
</plist>
# Convert XML output to JSON for jq
system_profiler -xml SPHardwareDataType | plutil -convert json -o - - | \
jq -r '.[0]._items[0].chip_type'
Output:
Apple M2 Pro
# Extract one key by path with plutil directly (no jq required)
system_profiler -xml SPHardwareDataType | \
plutil -extract "0._items.0.serial_number" raw -o - -
Output:
XXXXXXXXXXX
Detail levels
-detailLevel controls how much detail each probe collects. mini is the fastest but drops nested arrays (e.g. per-DIMM memory becomes just the total); full is the slowest and adds binary blobs you almost never need. The default depends on the data type — usually basic.
| Level | Behaviour | Typical use |
|---|---|---|
mini | Summarised, no nested arrays | Quick scripts that only need top-level values |
basic | Default for most data types | Day-to-day inspection |
full | Everything, including binary blobs and full firmware | Apple support diagnostics, deep audit |
# Compare detail levels for memory
system_profiler -detailLevel mini SPMemoryDataType | wc -l
system_profiler -detailLevel basic SPMemoryDataType | wc -l
system_profiler -detailLevel full SPMemoryDataType | wc -l
Output:
6
18
72
# Mini: just the total
system_profiler -detailLevel mini SPMemoryDataType
Output:
Memory:
Memory: 16 GB
Type: LPDDR5
Manufacturer: Hynix
Common data types in depth
The next several sections cover the data types you'll reach for most often. Each section shows a typical text dump, then a jq recipe to pull a specific value out.
SPDisplaysDataType — graphics + monitors
SPDisplaysDataType reports the GPU (or, on Apple Silicon, the integrated graphics block) and every connected display with its native resolution, refresh rate, colour space, and connection type (built-in / HDMI / USB-C / AirPlay).
system_profiler SPDisplaysDataType
Output:
Graphics/Displays:
Apple M2 Pro:
Chipset Model: Apple M2 Pro
Type: GPU
Bus: Built-In
Total Number of Cores: 16
Vendor: Apple (0x106b)
Metal Support: Metal 3
Displays:
Built-in Liquid Retina XDR Display:
Display Type: Built-in Liquid Retina XDR Display
Resolution: 3024 x 1964 Retina
Main Display: Yes
Mirror: Off
Online: Yes
Connection Type: Internal
DELL U2723QE:
Resolution: 3840 x 2160 (2160p/4K UHD)
UI Looks like: 1920 x 1080 @ 60.00Hz
Mirror: Off
Online: Yes
Rotation: Supported
# List every connected display with resolution
system_profiler -json SPDisplaysDataType | \
jq -r '.SPDisplaysDataType[].spdisplays_ndrvs[]? |
[._name, ._spdisplays_resolution // ._spdisplays_pixels] | @tsv'
Output:
Built-in Liquid Retina XDR Display 3024 x 1964 Retina
DELL U2723QE 3840 x 2160 (2160p/4K UHD)
SPMemoryDataType — RAM detail
On Intel Macs you get a per-DIMM breakdown (size, manufacturer, part number, ECC status). On Apple Silicon the RAM is on-package and reports as a single block.
system_profiler SPMemoryDataType
Output (Apple Silicon):
Memory:
Memory: 16 GB
Type: LPDDR5
Manufacturer: Hynix
Output (Intel):
Memory:
Memory Slots:
ECC: Enabled
Upgradeable Memory: Yes
BANK 0/DIMM0:
Size: 8 GB
Type: DDR4
Speed: 2666 MHz
Manufacturer: Samsung
Part Number: M471A1K43DB1-CTD
BANK 0/DIMM1:
Size: 8 GB
Type: DDR4
...
SPStorageDataType — every mounted volume
SPStorageDataType enumerates every Spotlight-indexable mount: the boot volume, every APFS sibling (Preboot, Recovery, Update, VM), external disks, USB sticks, and mounted DMGs.
system_profiler SPStorageDataType
Output:
Storage:
Macintosh HD:
Free: 245.32 GB (245,324,576,768 bytes)
Capacity: 494.38 GB (494,384,795,648 bytes)
Mount Point: /
File System: APFS
Writable: Yes
Ignore Ownership: No
BSD Name: disk3s1s1
Volume UUID: A8B4C5D6-E7F8-4901-A2B3-C4D5E6F70811
Physical Drive:
Device Name: APPLE SSD AP0512Z
Media Name: APPLE SSD Controller
Medium Type: SSD
Protocol: Apple Fabric
Internal: Yes
Partition Map Type: GPT
S.M.A.R.T. Status: Verified
# Free space on every mounted volume
system_profiler -json SPStorageDataType | jq -r '
.SPStorageDataType[] |
[._name,
.mount_point,
(.free_space_in_bytes / 1e9 | floor | tostring + " GB"),
(.size_in_bytes / 1e9 | floor | tostring + " GB")
] | @tsv'
Output:
Macintosh HD / 245 GB 494 GB
Backup /Volumes/Backup 1842 GB 2000 GB
USB /Volumes/USB 28 GB 128 GB
SPUSBDataType — USB topology
The USB tree is reported hierarchically: each root hub (built-in USB controller), then any external hubs, then leaf devices (keyboards, drives, cameras). Useful for diagnosing dead ports or finding the VID/PID of a misbehaving peripheral.
system_profiler SPUSBDataType
Output (excerpt):
USB:
USB 3.1 Bus:
Host Controller Driver: AppleEmbeddedUSBXHCIFL1100
PCI Device ID: 0x1100
PCI Revision ID: 0x0010
PCI Vendor ID: 0x1b73
Apple T2 Bus:
Apple T2 Controller:
Bluetooth USB Host Controller:
Product ID: 0x8290
Vendor ID: 0x05ac (Apple Inc.)
FaceTime HD Camera (Built-in):
Product ID: 0x8514
Vendor ID: 0x05ac (Apple Inc.)
Logitech USB Receiver:
Product ID: 0xc52b
Vendor ID: 0x046d (Logitech Inc.)
# Flat list of every USB device with vendor/product IDs
system_profiler -json SPUSBDataType | \
jq -r '[ .. | select(type=="object" and has("product_id"))? |
[._name, .vendor_id, .product_id] ] | .[] | @tsv'
Output:
Bluetooth USB Host Controller 0x05ac (Apple Inc.) 0x8290
FaceTime HD Camera (Built-in) 0x05ac (Apple Inc.) 0x8514
Logitech USB Receiver 0x046d (Logitech Inc.) 0xc52b
DELL U2723QE 0x413c (Dell Inc.) 0xb09e
SPNetworkDataType — interfaces and routes
SPNetworkDataType reports every network service with its order, type, IP addresses, gateway, DNS, and DHCP state.
system_profiler SPNetworkDataType
Output (excerpt):
Network:
Wi-Fi:
Type: AirPort
Hardware: AirPort
BSD Device Name: en0
IPv4:
Addresses: 192.168.1.42
Configuration Method: DHCP
Interface Name: en0
Router: 192.168.1.1
Subnet Masks: 255.255.255.0
DNS:
Server Addresses: 1.1.1.1, 8.8.8.8
DHCP Server Responses:
Lease Duration (seconds): 86400
Routers: 192.168.1.1
Server Identifier: 192.168.1.1
# Just the primary IPv4 of the first up interface
system_profiler -json SPNetworkDataType | jq -r '
.SPNetworkDataType[] |
select(.ip_address) |
[._name, .ip_address[0]] | @tsv' | head -1
Output:
Wi-Fi 192.168.1.42
SPApplicationsDataType — installed apps
SPApplicationsDataType lists every .app bundle on the system with its version, path, signature ("Apple", "Identified Developer", "None"), and Last-Modified date. Slow to enumerate (~5–30 seconds) on a typical Mac with hundreds of apps.
system_profiler SPApplicationsDataType | head -20
Output:
Applications:
1Password:
Version: 8.10.40
Obtained from: Identified Developer
Last Modified: 5/22/2026, 14:23
Kind: Apple Silicon
Signed by: Developer ID Application: AgileBits Inc. (2BUA8C4S2C)
Location: /Applications/1Password.app
Activity Monitor:
Version: 10.15
Obtained from: Apple
Last Modified: 5/15/2026, 09:00
Kind: Apple Silicon
Signed by: Software Signing
# Every app from "Identified Developer" (signed but not from Apple)
system_profiler -json SPApplicationsDataType | jq -r '
.SPApplicationsDataType[] |
select(.obtained_from == "identified_developer") |
[._name, .version, .path] | @tsv'
Output:
1Password 8.10.40 /Applications/1Password.app
Visual Studio Code 1.91.0 /Applications/Visual Studio Code.app
Firefox 126.0.1 /Applications/Firefox.app
Slack 4.39.0 /Applications/Slack.app
SPPowerDataType — battery + sleep
SPPowerDataType reports battery health, cycle count, current charge, AC adapter wattage, and the full sleep/wake configuration. The same info is available piecemeal from pmset -g batt and ioreg, but SPPowerDataType is the easy structured form.
system_profiler SPPowerDataType | sed -n '1,40p'
Output:
Power:
Battery Information:
Model Information:
Manufacturer: SMP
Device Name: bq40z651
Pack Lot Code: 0
PCB Lot Code: 0
Firmware Version: 1
Hardware Revision: 1
Cell Revision: 1543
Charge Information:
The battery's charge is full: No
Fully charged: No
Charging: Yes
State of Charge (%): 78
Health Information:
Cycle Count: 142
Condition: Normal
Maximum Capacity: 96%
AC Charger Information:
Connected: Yes
ID: 0x0000
Charging: Yes
Wattage (W): 96
Family: 0xe000400a
Serial Number: F1H2J3K4L5
Name: USB-C Power Adapter
# Cycle count and condition as a one-liner
system_profiler -json SPPowerDataType | jq -r '
.SPPowerDataType[]
| select(.sppower_battery_health_info)
| "Cycles: \(.sppower_battery_health_info.sppower_battery_cycle_count)\nHealth: \(.sppower_battery_health_info.sppower_battery_health)"'
Output:
Cycles: 142
Health: Normal
Combining multiple data types
You can pass any number of data type arguments and system_profiler returns them in one document. JSON output makes a single jq query trivial.
system_profiler -json SPHardwareDataType SPSoftwareDataType SPStorageDataType | \
jq '{
host: .SPSoftwareDataType[0].local_host_name,
model: .SPHardwareDataType[0].machine_name,
chip: .SPHardwareDataType[0].chip_type,
ram: .SPHardwareDataType[0].physical_memory,
serial: .SPHardwareDataType[0].serial_number,
os: .SPSoftwareDataType[0].os_version,
boot_vol: .SPSoftwareDataType[0].boot_volume,
total_gb: ([.SPStorageDataType[].size_in_bytes] | add / 1e9 | round),
free_gb: ([.SPStorageDataType[].free_space_in_bytes] | add / 1e9 | round)
}'
Output:
{
"host": "myhost",
"model": "MacBook Pro",
"chip": "Apple M2 Pro",
"ram": "16 GB",
"serial": "XXXXXXXXXXX",
"os": "macOS 15.5 (24F74)",
"boot_vol": "Macintosh HD",
"total_gb": 2622,
"free_gb": 2115
}
Performance and timeouts
A full default system_profiler (every data type) takes 30–60 seconds on a modern Mac and can hit 90+ seconds if a misbehaving USB device blocks the USB probe. Two strategies tame this: limit to the data types you actually need, and set -timeout to cap each probe.
# Time a focused query
time system_profiler -json SPHardwareDataType SPSoftwareDataType > /dev/null
Output:
system_profiler -json SPHardwareDataType SPSoftwareDataType > /dev/null
0.32 real 0.06 user 0.02 sys
# Vs the full kitchen sink
time system_profiler -json > /dev/null
Output:
system_profiler -json > /dev/null
42.18 real 8.41 user 4.32 sys
# Hard cap a slow probe (e.g. SPUSBDataType if a hub is misbehaving)
system_profiler -timeout 5 SPUSBDataType > /tmp/usb.txt 2>&1
echo "exit=$?"
Output:
exit=0
Comparison vs sysctl, ioreg, sw_vers
system_profiler is the inventory tool. For tight one-value lookups in scripts, three peers are faster:
| Need | Best tool | Example |
|---|---|---|
| One kernel/hw value (RAM, CPU count) | sysctl | sysctl -n hw.memsize |
| Live IORegistry (hardware, USB, sensors) | ioreg | ioreg -p IOUSB |
| macOS version + build | sw_vers | sw_vers -productVersion |
| Full structured inventory | system_profiler | system_profiler -json SPHardwareDataType |
| Pending updates | softwareupdate | softwareupdate -l |
# Three ways to get the chip name
system_profiler -json SPHardwareDataType | jq -r '.SPHardwareDataType[0].chip_type'
sysctl -n machdep.cpu.brand_string
ioreg -arc IOPlatformDevice -k product-name 2>/dev/null | \
plutil -extract '0."product-name"' raw -o - -
Output:
Apple M2 Pro
Apple M2 Pro
Apple M2 Pro
For a single field, sysctl is ~100× faster (sub-millisecond vs ~300 ms). For ten different fields with cross-cutting structure, system_profiler -json is more convenient.
Common pitfalls
- JSON output requires macOS 12+ — on older Macs use
-xmlplusplutil -convert json -o - -. - Whitespace inside
-listDataTypesoutput — the leading indentation differs slightly between macOS versions; trim before piping. - Some data types need root —
SPSmartCardsDataType,SPDiagnosticsDataType,SPInstallHistoryDataType(partial), andSPLogsDataTypereturn less info withoutsudo. Most hardware data types do not need root. SPApplicationsDataTypeis expensive — it scans every/Applications,~/Applications, and/System/Applications.appbundle and reads itsInfo.plist. 5–30 seconds typical. Cache the output for scripts that re-query.- JSON field names use snake_case, text dumps use Title Case — there is no automatic mapping. To find the JSON key for "Total Number of Cores", grep the JSON for the value:
system_profiler -json SPHardwareDataType | jq '..|select(type=="string")?|select(contains("10:6:4"))?'shows the surrounding key. - Two arrays for displays —
SPDisplaysDataTypereturns one item per GPU; each item hasspdisplays_ndrvscontaining the connected monitors. Forgetting this nesting gives you the GPU name when you wanted the monitor name. - Activation Lock and Serial Number leak PII — when sharing output publicly, redact
serial_number,provisioning_UDID, andplatform_UUID. SPUSBDataTypedeep nesting — devices behind hubs appear as_itemsinside their parent's_items. Use.. | objects | select(has("product_id"))in jq to flatten.-detailLevel fullenables more PII — full detail dumps FileVault recovery key SHAs, BootROM personalization, and other forensic data. Useminiorbasicfor inventory exports.- Timezone-sensitive date fields —
last_modifiedinSPApplicationsDataTypeis reported in local time without a tz marker. Convert withdate -j -fbefore storing in a UTC database. - No
--helpflag — usesystem_profiler -usageorsystem_profiler DATATYPE -usagefor per-type detail-level help. - Caching the wrong fields — Apple periodically renames JSON keys between macOS major versions (
chip_typewascpu_typeon Catalina). Pin keys per macOS version when writing long-lived inventory tooling.
Real-world recipes
One-line "what is this Mac?"
The fast inventory line you can SSH into any Mac to grab.
system_profiler -json SPHardwareDataType SPSoftwareDataType | jq -r '
"\(.SPSoftwareDataType[0].local_host_name) | \(.SPHardwareDataType[0].machine_name) | \(.SPHardwareDataType[0].chip_type) | \(.SPHardwareDataType[0].physical_memory) | \(.SPSoftwareDataType[0].os_version)"'
Output:
myhost | MacBook Pro | Apple M2 Pro | 16 GB | macOS 15.5 (24F74)
Fleet JSON inventory
A canonical snapshot per host, suitable for daily ingestion into an asset DB.
#!/bin/bash
# inventory.sh — emit JSON inventory of this Mac to stdout
set -euo pipefail
system_profiler -json \
SPHardwareDataType \
SPSoftwareDataType \
SPStorageDataType \
SPMemoryDataType \
SPPowerDataType \
SPNetworkDataType | \
jq '{
host: .SPSoftwareDataType[0].local_host_name,
timestamp: now | strftime("%Y-%m-%dT%H:%M:%SZ"),
model: .SPHardwareDataType[0].machine_name,
model_id: .SPHardwareDataType[0].machine_model,
chip: .SPHardwareDataType[0].chip_type,
cores: .SPHardwareDataType[0].number_processors,
serial: .SPHardwareDataType[0].serial_number,
ram_gb: (.SPHardwareDataType[0].physical_memory | gsub(" GB";"") | tonumber),
ram_type: .SPMemoryDataType[0].dimm_type,
os: .SPSoftwareDataType[0].os_version,
kernel: .SPSoftwareDataType[0].kernel_version,
sip: .SPSoftwareDataType[0].system_integrity,
boot_mode: .SPSoftwareDataType[0].boot_mode,
uptime: .SPSoftwareDataType[0].uptime,
storage: [.SPStorageDataType[] | {
name: ._name,
mount: .mount_point,
fs: .file_system,
size_gb: (.size_in_bytes / 1e9 | round),
free_gb: (.free_space_in_bytes / 1e9 | round)
}],
battery: (.SPPowerDataType[]?
| select(.sppower_battery_health_info)
| {
cycles: .sppower_battery_health_info.sppower_battery_cycle_count,
health: .sppower_battery_health_info.sppower_battery_health,
max_pct: .sppower_battery_health_info.sppower_battery_health_maximum_capacity
}),
primary_ip: (.SPNetworkDataType[]? | select(.ip_address) | .ip_address[0])
}'
Output: (saved as inventory.sh — run it below)
./inventory.sh
Output:
{
"host": "myhost",
"timestamp": "2026-05-25T10:30:15Z",
"model": "MacBook Pro",
"model_id": "Mac14,9",
"chip": "Apple M2 Pro",
"cores": "proc 10:6:4",
"serial": "XXXXXXXXXXX",
"ram_gb": 16,
"ram_type": "LPDDR5",
"os": "macOS 15.5 (24F74)",
"kernel": "Darwin 24.5.0",
"sip": "integrity_enabled",
"boot_mode": "boot_mode_normal",
"uptime": "up 5 days, 14:22",
"storage": [
{ "name": "Macintosh HD", "mount": "/", "fs": "APFS", "size_gb": 494, "free_gb": 245 }
],
"battery": { "cycles": 142, "health": "Normal", "max_pct": "96%" },
"primary_ip": "192.168.1.42"
}
Inventory across SSH'd fleet
A loop that collects the snapshot from each host into a single line-delimited JSON file.
#!/bin/bash
> fleet-inventory.jsonl
for host in mac01 mac02 mac03 mac04 mac05; do
echo "Probing $host..."
ssh "$host" 'cat /usr/local/bin/inventory.sh | bash' >> fleet-inventory.jsonl
done
echo "Hosts: $(wc -l < fleet-inventory.jsonl)"
Output:
Probing mac01...
Probing mac02...
Probing mac03...
Probing mac04...
Probing mac05...
Hosts: 5
# Query the inventory with jq
jq -r '. | [.host, .model, .chip, .ram_gb, .battery.cycles] | @tsv' fleet-inventory.jsonl
Output:
mac01 MacBook Pro Apple M2 Pro 16 142
mac02 MacBook Air Apple M2 8 57
mac03 Mac mini Apple M2 Pro 32 0
mac04 iMac Apple M1 16 0
mac05 MacBook Pro Apple M3 Max 64 23
Find every Intel-only app on this Mac
Apple Silicon migration audit: which .apps are still x86_64-only (will require Rosetta)?
system_profiler -json SPApplicationsDataType | jq -r '
.SPApplicationsDataType[] |
select(.arch_kind == "arch_i64") |
[._name, .version, .path] | @tsv'
Output:
LegacyTool 2.1.0 /Applications/LegacyTool.app
OldKitApp 5.7.3 /Applications/OldKitApp.app
Find the largest .app bundles on disk
Storage-cleanup tool: rank apps by disk footprint.
system_profiler -json SPApplicationsDataType | jq -r '
.SPApplicationsDataType[] | [._name, .path] | @tsv' | \
while IFS=$'\t' read -r name path; do
size=$(du -sh "$path" 2>/dev/null | cut -f1)
printf "%-10s %s\n" "$size" "$name"
done | sort -rh | head -10
Output:
8.4G Xcode
4.1G Affinity Photo
2.8G Microsoft Word
2.6G Visual Studio Code
1.9G Final Cut Pro
Detect a stale BootROM
For organisations that need every Mac on a known-good BootROM firmware version.
EXPECTED="10151.121.1"
ACTUAL=$(system_profiler -json SPHardwareDataType | jq -r '.SPHardwareDataType[0].boot_rom_version')
if [[ "$ACTUAL" == "$EXPECTED" ]]; then
echo "BootROM OK ($ACTUAL)"
else
echo "BootROM drift: have=$ACTUAL want=$EXPECTED"
fi
Output:
BootROM OK (10151.121.1)
Diagnose a flaky USB hub
When lsusb would say "device is glitching" on Linux, here's the Mac equivalent.
# Snapshot 1
system_profiler -json SPUSBDataType > /tmp/usb-before.json
# Trigger / wait / re-snapshot
sleep 30
system_profiler -json SPUSBDataType > /tmp/usb-after.json
# Diff just the leaf device names
diff <(jq -r '..|objects|select(has("product_id"))?._name' /tmp/usb-before.json | sort) \
<(jq -r '..|objects|select(has("product_id"))?._name' /tmp/usb-after.json | sort)
Output:
3d2
< Logitech USB Receiver
(A USB device disappeared between snapshots — physical port flake or driver issue.)
Export a PDF for a support ticket
Apple Support frequently asks for a full System Information report. The GUI lets you "File → Export → Send to Apple"; the CLI equivalent is plain text into a PDF via cupsfilter or enscript.
system_profiler -detailLevel full > ~/Desktop/sysinfo-$(date +%Y%m%d).txt
# Optional: convert to PDF
textutil -convert webarchive -inputencoding UTF-8 ~/Desktop/sysinfo-*.txt -output ~/Desktop/sysinfo.webarchive
Output: (none — files written)
Spot kernel extensions installed by third parties
Kernel extensions are deprecated but still present on older deployments. List anything not signed by Apple.
system_profiler -json SPExtensionsDataType | jq -r '
.SPExtensionsDataType[]
| select(.signed_by != "Software Signing" and .signed_by != null)
| [.spext_bundle_id, .spext_version, .signed_by] | @tsv' | head -20
Output:
com.crowdstrike.kext 7.20.16404 Developer ID Application: CrowdStrike, Inc.
com.parallels.kext.hypervisor 19.4.0 Developer ID Application: Parallels International GmbH
For a continuously-updated inventory dashboard, run the JSON inventory script via a launchd
StartCalendarIntervalagent and have it POST to your central inventory API. Seelaunchctlfor the plist pattern.
[!WARN] Never ship raw
system_profileroutput to a public bug tracker. It containsserial_number,platform_UUID, IP addresses, MAC addresses, paired Bluetooth device names, and Wi-Fi network names. Redact before sharing.
Sources
References consulted while writing this article. Links open in a new tab.
- Apple Developer — system_profiler(8) man page — Authoritative flag list, data-type names, and detail levels used while writing the options reference.
- SS64 — system_profiler — Cross-version notes.
See also
macos-cli— broader macOS terminal reference (sw_vers,sysctl,ioreg).softwareupdate— patch-level inventory and update install.jq— JSON query language used throughout the recipes here.systeminfo— Windows analogue for fleet-level OS/hardware inventory.