Skip to content

Instantly share code, notes, and snippets.

@dobesv
Created June 15, 2026 18:10
Show Gist options
  • Select an option

  • Save dobesv/e19d7a14b4ab8f8176beeb700d5feb45 to your computer and use it in GitHub Desktop.

Select an option

Save dobesv/e19d7a14b4ab8f8176beeb700d5feb45 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# install-ev-serial.sh
#
# Give a DIY / no-factory-serial Linux box a unique system serial number (and,
# optionally, a model name) for Google Workspace Endpoint Verification —
# WITHOUT touching the BIOS/flash.
#
# How it works:
# * Endpoint Verification's helper (device_state.sh) reads the serial from
# /sys/class/dmi/id/product_serial and the model from product_name.
# * We bind-mount a file containing the chosen value(s) over those sysfs
# entries (the kernel-exported DMI data; nothing is written to flash).
# * A systemd unit re-applies the bind-mount on every boot, ordered BEFORE
# endpoint-verification.service so EV caches the right value.
# * We then refresh EV's cache so the change takes effect immediately.
#
# Usage:
# ./install-ev-serial.sh <SERIAL> [MODEL] # re-execs under sudo if needed
# sudo ./install-ev-serial.sh <SERIAL> [MODEL]
# sudo ./install-ev-serial.sh --remove # uninstall / roll back
#
# SERIAL is required. A UUID makes a good, guaranteed-unique value; generate
# one with: uuidgen
#
# Examples:
# ./install-ev-serial.sh "$(uuidgen)"
# ./install-ev-serial.sh "$(uuidgen)" "ASUS PRIME X670-P WIFI"
#
set -euo pipefail
# ---- configuration (paths are hard-coded in the unit too; keep in sync) ----
OVERRIDE_DIR=/etc/dmi-override
UNIT_NAME=dmi-serial-override.service
UNIT_PATH=/etc/systemd/system/${UNIT_NAME}
DMI_DIR=/sys/class/dmi/id
EV_SERVICE=endpoint-verification.service
EV_ATTRS=/opt/google/endpoint-verification/var/lib/device_attrs
# ---- pretty output (no color if not a tty) ----
if [ -t 1 ]; then C_OK=$'\033[1;32m'; C_WARN=$'\033[1;33m'; C_ERR=$'\033[1;31m'; C_OFF=$'\033[0m'
else C_OK=; C_WARN=; C_ERR=; C_OFF=; fi
say() { printf '%s==>%s %s\n' "$C_OK" "$C_OFF" "$*"; }
warn() { printf '%s[warn]%s %s\n' "$C_WARN" "$C_OFF" "$*" >&2; }
die() { printf '%s[error]%s %s\n' "$C_ERR" "$C_OFF" "$*" >&2; exit 1; }
usage() {
cat <<'USAGE'
install-ev-serial.sh — set a unique system serial for Google Endpoint
Verification without flashing the BIOS.
Usage:
install-ev-serial.sh <SERIAL> [MODEL] # SERIAL is required
install-ev-serial.sh --remove # uninstall / roll back
install-ev-serial.sh --help
A UUID makes a good, guaranteed-unique serial. Generate one with: uuidgen
Examples:
install-ev-serial.sh "$(uuidgen)"
install-ev-serial.sh "$(uuidgen)" "ASUS PRIME X670-P WIFI"
USAGE
}
# ---- handle --help before anything that needs root ----
case "${1:-}" in
-h|--help) usage; exit 0 ;;
esac
# ---- require an argument before elevating (so we don't prompt for a password
# just to error out on a missing serial) ----
if [ "$#" -eq 0 ]; then
usage >&2
die "SERIAL is required — generate one with: $0 \"\$(uuidgen)\""
fi
# ---- re-exec under sudo if not root ----
if [ "$(id -u)" -ne 0 ]; then
say "Elevating with sudo..."
SELF="$(readlink -f "$0")"
exec sudo bash "$SELF" "$@"
fi
# ---- parse action ----
ACTION=install
SERIAL=""
MODEL=""
case "${1:-}" in
-r|--remove|--uninstall) ACTION=remove ;;
"") usage >&2; die "SERIAL is required — generate one with: $0 \"\$(uuidgen)\"" ;;
-*) die "Unknown option: $1" ;;
*) SERIAL="$1"; MODEL="${2:-}" ;;
esac
# ===========================================================================
# Remove / roll back
# ===========================================================================
if [ "$ACTION" = remove ]; then
say "Removing DMI serial override"
systemctl disable --now "$UNIT_NAME" >/dev/null 2>&1 || true
for n in product_serial product_name; do
if mountpoint -q "$DMI_DIR/$n"; then
umount "$DMI_DIR/$n" || warn "could not umount $DMI_DIR/$n"
fi
done
rm -f "$UNIT_PATH"
rm -rf "$OVERRIDE_DIR"
systemctl daemon-reload
if systemctl list-unit-files 2>/dev/null | grep -q "^${EV_SERVICE}"; then
say "Refreshing Endpoint Verification cache"
systemctl restart "$EV_SERVICE" || warn "could not restart $EV_SERVICE"
fi
say "Done. sysfs serial is back to: $(cat "$DMI_DIR/product_serial" 2>/dev/null || echo '<unreadable>')"
exit 0
fi
# ===========================================================================
# Install
# ===========================================================================
# ---- preflight + validation ----
[ -e "$DMI_DIR/product_serial" ] || die "$DMI_DIR/product_serial does not exist (no SMBIOS/DMI on this system?)."
case "$SERIAL" in *\"*) warn "Serial contains a double-quote; EV strips those, so the reported value will differ." ;; esac
[ "${#SERIAL}" -le 128 ] || warn "Serial is ${#SERIAL} chars; EV truncates to 128."
say "Serial to report: \"$SERIAL\""
[ -n "$MODEL" ] && say "Model to report: \"$MODEL\""
# ---- write the override value(s) ----
say "Writing override values to $OVERRIDE_DIR"
install -d -m 0755 "$OVERRIDE_DIR"
printf '%s\n' "$SERIAL" > "$OVERRIDE_DIR/product_serial"
chmod 0444 "$OVERRIDE_DIR/product_serial"
if [ -n "$MODEL" ]; then
printf '%s\n' "$MODEL" > "$OVERRIDE_DIR/product_name"
chmod 0444 "$OVERRIDE_DIR/product_name"
else
# If re-running without a model, drop any previous model override.
rm -f "$OVERRIDE_DIR/product_name"
fi
# ---- install the persistence unit (binds every file in OVERRIDE_DIR) ----
say "Installing systemd unit $UNIT_PATH"
cat > "$UNIT_PATH" <<'UNIT_EOF'
[Unit]
Description=Override DMI product_serial/product_name for Endpoint Verification (DIY board, no factory serial)
DefaultDependencies=no
After=local-fs.target
Before=endpoint-verification.service
ConditionPathExists=/etc/dmi-override/product_serial
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'for f in /etc/dmi-override/*; do n=$(basename "$f"); mountpoint -q "/sys/class/dmi/id/$n" || mount --bind "$f" "/sys/class/dmi/id/$n"; done'
ExecStop=/bin/sh -c 'for f in /etc/dmi-override/*; do n=$(basename "$f"); ! mountpoint -q "/sys/class/dmi/id/$n" || umount "/sys/class/dmi/id/$n"; done'
[Install]
WantedBy=multi-user.target
UNIT_EOF
# ---- (re)apply the bind-mount(s) now and on every boot ----
systemctl daemon-reload
systemctl enable "$UNIT_NAME" >/dev/null 2>&1 || true
say "Applying bind-mount(s)"
systemctl restart "$UNIT_NAME"
# ---- refresh Endpoint Verification's cached attributes ----
if systemctl list-unit-files 2>/dev/null | grep -q "^${EV_SERVICE}"; then
say "Refreshing Endpoint Verification cache"
systemctl restart "$EV_SERVICE" || warn "could not restart $EV_SERVICE"
else
warn "$EV_SERVICE not found — skipping EV refresh (override is still active)."
fi
# ---- report result ----
echo
say "Result"
printf ' %-34s = %s\n' "$DMI_DIR/product_serial" "$(cat "$DMI_DIR/product_serial")"
[ -e "$OVERRIDE_DIR/product_name" ] && printf ' %-34s = %s\n' "$DMI_DIR/product_name" "$(cat "$DMI_DIR/product_name")"
if [ -r "$EV_ATTRS" ]; then
echo " Endpoint Verification cache ($EV_ATTRS):"
sed 's/^/ /' "$EV_ATTRS"
fi
cat <<EOF
Done. Notes:
* \`dmidecode\` will still show the old placeholder — expected; EV reads sysfs, not dmidecode.
* The new value uploads on EV's next sync (~10 min) or when you open the
Endpoint Verification extension. Confirm in Admin console > Devices.
* Roll back any time: sudo $0 --remove
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment